双重转义或反转义¶
ID: js/double-escaping
Kind: problem
Security severity: 7.8
Severity: warning
Precision: high
Tags:
- correctness
- security
- external/cwe/cwe-116
- external/cwe/cwe-020
Query suites:
- javascript-code-scanning.qls
- javascript-security-extended.qls
- javascript-security-and-quality.qls
在不受信任的输入中转义元字符是防止注入攻击(如跨站脚本)的重要技术。其中一个具体示例是 HTML 实体编码,它将 HTML 特殊字符替换为 HTML 字符实体,以防止它们被解释为 HTML 标记。例如,小于号被编码为
,双引号被编码为<
。其他示例包括反斜杠转义,用于在字符串文字中包含不受信任的数据,以及百分比编码,用于 URI 组件。"
将转义序列替换为它们表示的字符的反向过程称为反转义。
请注意,转义字符本身(例如,在 HTML 编码的情况下为&号)在转义和反转义过程中起着特殊的作用:它们本身被转义,但也构成其他字符的转义表示形式的一部分。因此,必须小心避免双重转义和反转义:转义时,必须首先转义转义字符,反转义时,必须最后反转义它。
如果在清理的上下文中使用,双重反转义可能会使清理无效。即使它没有在安全关键的上下文中使用,它仍然可能导致输出混乱或乱码。
建议¶
尽可能使用(经过良好测试的)清理库。与自定义实现相比,这些库更有可能正确处理极端情况。对于 URI 编码,可以使用标准的
和encodeURIComponent
函数。decodeURIComponent
否则,请确保始终先转义转义字符,最后反转义它。
示例¶
以下示例显示了一对手工编写的 HTML 编码和解码函数
module.exports.encode = function(s) {
return s.replace(/&/g, "&")
.replace(/"/g, """)
.replace(/'/g, "'");
};
module.exports.decode = function(s) {
return s.replace(/&/g, "&")
.replace(/"/g, "\"")
.replace(/'/g, "'");
};
编码函数在其他字符之前正确处理了&号。例如,字符串
被编码为me & "you"
,字符串me & "you"
被编码为"
。&quot;
但是,解码函数在处理其他字符之前,错误地将
解码为&
。因此,虽然它正确地解码了上面的第一个示例,但它将第二个示例(&
)解码为&quot;
(单个双引号),这不是正确的。"
相反,解码函数应该最后解码&号
module.exports.encode = function(s) {
return s.replace(/&/g, "&")
.replace(/"/g, """)
.replace(/'/g, "'");
};
module.exports.decode = function(s) {
return s.replace(/"/g, "\"")
.replace(/'/g, "'")
.replace(/&/g, "&");
};
参考资料¶
OWASP Top 10:A1 注入.
npm:html-entities 包。
npm:js-string-escape 包。
通用弱点枚举:CWE-116.
通用弱点枚举:CWE-20.