经过几个小时的错误搜索,我找到了我最烦人的错误之一的原因。
当用户在我的网站上键入消息时,他们可以使用纯文本和 html 实体为其标题。
这意味着在某些情况下,用户将键入带有常见 html 实体图片的标题,如下所示。( ͡° ͜ʖ ͡°) .
为了防止 html 注入,我在标题上使用 htmlspecialchars(),令人讨厌的是,当稍后输出到页面上时,它会将图片转换为 html 实体格式。
( ͡° ͜ʖ ͡°)
我意识到这里的问题是标题被编码为上面的示例,htmlspecialchar 以及做我想做的事情并编码可能的 html 注入,正在将实体中的与号转换为
&.
通过取消所有与号的转义,并将它们改回&这解决了我的问题,脸会按预期出现。
但是,我不确定这是否仍然可以免受恶意 html 的影响。解码用户估算标题中的与号是否安全?如果没有,我该如何解决此问题?
如果您的实体显示为文本,则您可能调用htmlspecialchars()
两次。
如果未显式调用htmlspecialchars()
两次,则可能是浏览器端自动转义,如果包含表单的页面使用过时的单字节编码(如 Windows-1252)。这种自动转义是正确表示特定单字节编码的字符集中不存在的字符的唯一方法。所有当前的浏览器(包括Firefox,Opera和IE)都这样做。
确保您使用的是 Unicode(尤其是 UTF-8)编码。
若要使用 Unicode 作为编码,请将 <meta charset="utf-8" />
元素添加到包含表单的 HTML 页的HEAD
部分。并且不要忘记以 UTF-8 编码保存 HTML 页面本身。要在PHP中使用Unicode,通常使用多字节(mb_
前缀)字符串函数就足够了。最后,像MySQL这样的数据库引擎很久以前就支持UTF-8。
作为临时解决方法,您可以通过将htmlspecialchars()
函数的第 4 个参数 ($double_encode
) 设置为 false
来禁用对现有实体的重新编码。
没有直接的答案。您可能会<script...>
<script...>
并最终遇到麻烦,但是看起来代码已被双重编码 - 可能在输入时一次,然后在输出到屏幕时再次。如果您可以保证它已被双重编码,那么撤消其中一个应该是安全的。
但是,最好的解决方案是将"原始"值保留在内存中,并进行清理/编码以输出到数据库,html,JSON等中。
所以 - 当你得到输入时,清理它是否有任何你不想要的东西,但不要在这个阶段实际将其转换为 HTML 或转义它或其他任何东西。将其转义到数据库中,在输出到屏幕/xml等时对其进行html编码。