UTF-8字符不是XSS漏洞

时间:2009-04-30 01:00:11

标签: php utf-8 xss

我正在研究编码字符串以防止XSS攻击。现在我们想要使用白名单方法,其中白名单之外的任何字符都将被编码。 现在,我们正在采取'('和'输出'('之类的东西。据我们所知,这将阻止大多数XSS。

问题是我们有很多国际用户,当整个网站都是日语时,编码成为主要的带宽需求。是否可以肯定地说,基本ASCII集之外的任何字符都不是漏洞,它们不需要编码,或者是否仍然需要编码的ASCII集之外的字符?

2 个答案:

答案 0 :(得分:11)

如果您只是将编码传递给htmlentities() / htmlspecialchars

,可能会(很多)
echo htmlspecialchars($string,  ENT_QUOTES, 'utf-8');

但是,如果这是否足够取决于你正在打印什么(以及在哪里)。

另见:
http://shiflett.org/blog/2005/dec/googles-xss-vulnerability
http://jimbojw.com/wiki/index.php?title=Sanitizing_user_input_against_XSS
http://www.erich-kachel.de/?p=415(德语。如果我发现英语类似的东西 - >更新)编辑:嗯,我想你可以得到主要观点而不会说一口德语;) 字符串

javascript:eval(String.fromCharCode(97,108,101,114,116,40,39,88,83,83,39,41)) 
传递htmlentities()不变。现在考虑将
<a href="<?php echo htmlentities($_GET['homepage']); ?>"
这样的内容发送到浏览器
<a href="javascript:eval(String.fromCharCode(97,108,101,114,116,40,39,88,83,83,39,41))">
。归结为
href="javascript:eval(\"alert('XSS')\")"
虽然htmlentities()可以完成元素内容的工作,但它对于属性来说并不是那么好。

答案 1 :(得分:5)

一般来说,是的,你可以依赖任何非ascii来“安全”,但是有一些非常重要的需要考虑:

  1. 始终确保您拥有的一切 发送给客户的标记为 UTF-8。这意味着有一个标题 明确说“内容类型: 为text / html; charset = utf-8“on every 单页,包括您的所有内容 错误页面,如果有任何内容 这些错误页面是从中生成的 用户输入。 (很多人忘记了 测试他们的404页面,并有 页面包括未完成的URL(逐字)
  2. 始终确保 你发给客户的是什么 有效的UTF-8。这意味着你 不能简单地通过 从用户收到的字节返回 用户再次。你需要解码 字节为UTF-8,应用你的html编码XSS预防,然后编码 当你把它们写回来时,它们就像UTF-8一样 进行。
  3. 这两个警告中的第一个是让客户端的浏览器看不到包含高字母字符和回退到某些本地多字节字符集的东西。该本地多字节字符集可能有多种方法来指定您无法防范的有害ascii字符。与此相关,某些浏览器的某些旧版本 - 咳嗽咳嗽 - 在检测到页面为UTF-7时有点过于苛刻;这开启了XSS可能性的终结。为了防止这种情况,您可能需要确保对任何传出的“+”符号进行html编码;当你生成正确的Content-Type标题时,这是过度的偏执,但是当一些未来的人翻转关闭你的自定义标题的开关时,它会保存你。 (例如,通过在应用程序前放置配置不当的缓存反向代理,或者通过执行某些操作来插入额外的横幅标题 - 如果已经写入任何输出,php将不允许您设置任何HTTP标头)

    第二个是因为在UTF-8中可以指定“过短”序列,虽然在当前规范下无效,但旧版浏览器会将其解释为ASCII字符。 (See what wikipedia has to say)此外,有人可能会在请求中插入一个坏字节;如果你将这个包传递给用户,它可能会导致某些浏览器用“?”替换坏字节和后面的一个或多个字节。或其他一些“无法理解这个”的角色。也就是说,一个坏字节可能会导致一些好的字节被吞没。如果你仔细观察你输出的内容,可能会有一个地方,一个能够从输出中擦除一两个字节的攻击者可以做一些XSS。将输入解码为UTF-8然后重新编码可防止此攻击向量。