.text() 是否可以安全地清理数据? [JQuery]

Is .text() safe or not to sanitize data? [JQuery]

我看到这个问题已经在别处问过:

Escaping HTML strings with jQuery

@travis 标记为正确的答案说 .text() 没问题。然而,有些人在评论中提到(例如@nivcaner 和@lior)这个解决方案并不好。我们站在哪里?我可以安全地使用它吗?

我正在开发一个网络应用程序,用户可以在浏览器中创建一个文档,其中可以通过 JQuery 添加 tables、headers 和视频。当用户 "saves" 他的文档时,它的结构被翻译成一个数组,其中数组的所有元素都由 "pure" 文本组成,没有标签(例如每个 [=43= 有一个数组元素) ] 包含该单元格文本的单元格等)。然后将数组转换为 JSON 格式并发送到服务器,并通过 PHP.

以 JSON 格式处理/清理/保存

之后,该文档就可以被其他用户访问,这当然会引入潜在的安全漏洞。他们的想法是,他们从服务器读取 JSON 数据,然后在客户端通过 javascript/JQuery 重新创建文档。

虽然我非常有信心我的 PHP 代码能够正确清理 JSON 数据,但我担心恶意用户可能会欺骗其他用户阅读的一些攻击JSON 来自不受信任来源的数据。出于这个原因,我觉得最好在客户端验证 re-creating tables 之前来自服务器的任何 JSON 数据等。假设变量 currentCellText 保存要写入 table 单元格 #mytd 的(JSON 读取)文本,我可以安全地使用代码 $("#mytd").text(currentCellText) 来 re-create单元格内容?

来自jQuery .text() article

We need to be aware that this method escapes the string provided as necessary so that it will render correctly in HTML. To do so, it calls the DOM method .createTextNode(), does not interpret the string as HTML.

这意味着数据被存储到文本节点,根据规范不能将存储的文本呈现为 HTML,因此使用 $("#mytd").text(currentCellText) 应该是安全的。

jQuery 实现的 1.x 行支持本文。当您查看 jQuery 1.11.3 的未压缩源代码时,您会发现:

jQuery.fn.extend({
    text: function( value ) {
        return access( this, function( value ) {
            return value === undefined ?
                jQuery.text( this ) :
                this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
        }, null, value, arguments.length );
    },
    ...

相关行是这样的:

this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );

该行的大部分内容只是简单地定位用于创建文本节点的正确 document,但是作为传入字符串的 value 永远不会直接被解释为 HTML.

此外,查看 jQuery 2.1.4 的未压缩代码,您会发现该实现使用 .textContent 属性进行赋值,这依赖于浏览器实现来完全清理传递的文本,而不是部分文本:

jQuery.fn.extend({
    text: function( value ) {
        return access( this, function( value ) {
            return value === undefined ?
                jQuery.text( this ) :
                this.empty().each(function() {
                    if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
                        this.textContent = value;
                    }
                });
        }, null, value, arguments.length );
    },
    ...

这段代码的相关部分在这里:

this.empty().each(function() {
    if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
        this.textContent = value;
    }
});

因为这是将参数传递给 .text() 函数时执行的内容。