6

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

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

4

2 回答 2

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() 完成了元素内容的工作,但它对属性并不是那么好。

于 2009-04-30T01:05:06.797 回答
5

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

  1. 始终确保您发送给客户端的内容被标记为 UTF-8。这意味着在每个页面上都有一个明确表示“Content-Type: text/html; charset=utf-8”的标题,如果这些错误页面上的任何内容是从用户输入生成的,则包括所有错误页面。(许多人忘记测试他们的 404 页面,并让该页面逐字包含未找到的 URL)
  2. 始终确保您发送给客户端的内容是有效的 UTF-8。这意味着您 不能简单地将从用户收到的字节再次传递给用户。您需要将字节解码为 UTF-8,应用您的 html 编码 XSS 防护,然后在将它们写回时将它们编码为 UTF-8。

这两个警告中的第一个是防止客户端的浏览器看到一堆东西,包括高字母字符和回退到一些本地多字节字符集。该本地多字节字符集可能有多种方法来指定您不会防御的有害 ascii 字符。与此相关,某些浏览器的一些旧版本-咳咳- 在检测页面是 UTF-7 时有点过于急切;这开辟了无限的 XSS 可能性。为了防止这种情况,您可能需要确保对任何传出的“+”符号进行 html 编码;当您生成正确的 Content-Type 标头时,这是过度的偏执狂,但是当将来有人打开关闭您的自定义标头的开关时,这会为您节省。(例如,通过在您的应用程序前面放置一个配置不当的缓存反向代理,或者通过做一些事情来插入一个额外的横幅标头 - 如果任何输出已经写入,php 将不允许您设置任何 HTTP 标头)

第二个是因为在 UTF-8 中可以指定“过短”的序列,虽然在当前规范下无效,但旧浏览器会将其解释为 ASCII 字符。(看看维基百科怎么说)另外,有人可能会在请求中插入一个坏字节;如果您将此包传递给用户,它可能会导致某些浏览器将坏字节及其后面的一个或多个字节替换为“?” 或其他一些“无法理解”的角色。也就是说,一个坏字节可能会导致一些好字节也被吞掉。如果您仔细查看您正在输出的内容,则可能在某个地方,能够从输出中擦除一两个字节的攻击者可以执行一些 XSS。

于 2009-05-19T12:14:12.027 回答