PHP:如果客户端将字符集不匹配(htmlentities UTF-8)视为 ISO-8859-1(反之亦然)

信息安全 php xss 编码 统一码
2021-08-31 00:11:53

简短的问题:

问题:如果服务器以 UTF-8 运行 htmlentities 但客户端将结果视为 ISO-8859-1,是否会出现任何安全漏洞?

假设:使用一个一致的字符集时不存在漏洞


详细问题:

问题:如果服务器 htmlentities 将 ISO-8859-1 字符串作为 UTF-8,是否会出现任何安全漏洞?(并且客户端将结果解释为 ISO-8859-1?)

(例如$results = htmlentities($iso_8859_1_string, ENT_QUOTES, "UTF-8")

假设所有内容都以这样一种方式编码,即当始终使用一种字符集编码时不会出现漏洞。(忽略 $results = 空字符串)。

也许如果$iso_8859_1_string可以包含任何值,则结果将被视为无效的 UTF-8(并返回“”)或有效的 UTF-8。对于有效的 UTF-8,UTF-8 序列将按预期转义,但在将结果解释为 ISO-8859-1 的客户端上如何查看结果?0 - 127 范围内的字符按预期转义(与“US-ASCII”相同),某些字符将解析为 html 实体并可以按预期显示。在 128+ 范围内是否存在无法解析为 html 实体的有效 UTF-8 字符?客户端会不会只看到一堆乱码/垃圾文本/符号,但看不到会导致 Web 浏览器执行代码或切换到代码执行上下文的字符?(例如,没有标签字符,例如'<' '>' 符号)?(假设 $results 被放入一个 "

这是正确的思路吗?


注意:我相信我已经解决了反之亦然的情况(即,如果服务器将 UTF-8 字符串作为 ISO-8859-1 并且客户端将结果解释为 UTF-8)

(例如htmlentities($utf8_string, ENT_QUOTES, "ISO-8859-1")

回答:我的猜测是客户端上没有安全漏洞(对于 htmlentities 作为 ISO -> 客户端读取为 UTF-8),因为:

  • 在 ISO-8859-1 中,范围内的字符:

    • 0-127 (US-ASCII):在 UTF-8 中以完全相同的方式编码,
    • ISO-8859-1 中的 160 -> 255 都将被编码为 HTML 实体,
    • 只留下 128-159 字符范围...,但根据 Wikipedia 的 UTF-8 规范http://en.wikipedia.org/wiki/UTF-8#Description,所有 UTF-8 字节都在 128+范围都是“多字节序列”的一部分,其中包括始终为 192 或更高的“前导字节”和 128+ 范围内的“连续字节”。因此,htmlentities($utf8_string, ENT_QUOTES, "ISO-8859-1")无法输出 UTF-8 生成有效多字节序列所需的任何“前导字节”。因此,此范围内的任何字符都会在 UTF-8 中显示为 ? (即无效字符),因为没有看到任何“前导字节”。

我认为这解决了我对另一个方向的问题。


实际情况:具有安全反向端口的 PHP 5.3.x 服务器使用 ISO-8859-1 作为默认编码。从 PHP 5.4 开始,UTF-8 是默认编码。 http://php.net/htmlentities我想确定代码是否在全 UTF-8 或全 ISO-8859-1 环境中正常工作,并确保不存在由编码错误/不匹配引起的自动安全漏洞。

我觉得我可以放心,只有可用性会受到影响,而在这些特定情况下不会影响安全性。

2个回答

据我所知,没有安全问题。

HTML 中的“危险”字符(小于、大于、与号、单引号、双引号)在 UTF-8 和 ISO-8859-1(以及几乎所有其他您可能使用的编码)下都具有相同的字节值遇到,但 UTF-16、UTF-32 和 EBCDIC 除外)。因此,在一种编码中转义它们也会在另一种编码中转义它们。

之所以如此,是因为绝大多数字符编码,包括 UTF-8 和 ISO-8859-1,都是“ASCII 加附加字符”,而 HTML 文档的结构仅使用编码的 ASCII 部分中的字符.

据我所知,只要您的 PHP 脚本(即表单)使用 htmlspecialchars() 过滤器并去除奇怪符号和反斜杠之类的东西,至少从我的角度来看,不会有安全风险。

但是,对于我们偏执的人来说,强制客户使用字符集是一种选择,以及我刚刚命名的基本内容。