CodeQL 文档

双重转义或反转义

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

点击查看 CodeQL 代码库中的查询

在不受信任的输入中转义元字符是防止注入攻击(如跨站脚本)的重要技术。其中一个具体示例是 HTML 实体编码,它将 HTML 特殊字符替换为 HTML 字符实体,以防止它们被解释为 HTML 标记。例如,小于号被编码为<,双引号被编码为"。其他示例包括反斜杠转义,用于在字符串文字中包含不受信任的数据,以及百分比编码,用于 URI 组件。

将转义序列替换为它们表示的字符的反向过程称为反转义。

请注意,转义字符本身(例如,在 HTML 编码的情况下为&号)在转义和反转义过程中起着特殊的作用:它们本身被转义,但也构成其他字符的转义表示形式的一部分。因此,必须小心避免双重转义和反转义:转义时,必须首先转义转义字符,反转义时,必须最后反转义它。

如果在清理的上下文中使用,双重反转义可能会使清理无效。即使它没有在安全关键的上下文中使用,它仍然可能导致输出混乱或乱码。

建议

尽可能使用(经过良好测试的)清理库。与自定义实现相比,这些库更有可能正确处理极端情况。对于 URI 编码,可以使用标准的encodeURIComponentdecodeURIComponent函数。

否则,请确保始终先转义转义字符,最后反转义它。

示例

以下示例显示了一对手工编写的 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",字符串"被编码为"

但是,解码函数在处理其他字符之前,错误地将&解码为&。因此,虽然它正确地解码了上面的第一个示例,但它将第二个示例(")解码为"(单个双引号),这不是正确的。

相反,解码函数应该最后解码&号

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, "&");
};

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私