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