转义 JavaScript 常量

信息安全 应用安全 Web应用程序 xss javascript
2021-09-03 15:58:52

不受信任的值如何作为 javascript 字符串常量包含在 html 页面中?虽然我问的案例使用 JSF 和 Rails,但我认为这是一个独立于服务器端框架的一般问题。

属性

在 on-attributes 中逃避 \'" 显然是不够的:

onclick='alert("[variable]")'
variable: hello, world"); alert("XSS
result: alert("hello, world"); alert("XSS")

在 Firefox 中,这将显示一个“hello, world”和一个“XSS”警报对话框。由于变量不包含 ",Rails 函数escape_javascript在这种情况下是不够的。应用 html 转义似乎是安全的,因为在这种情况下只显示原始对话框:

result: onlick='alert("hello, world"); alert("XSS")'

脚本标签

然而,在 <script> 标签中,Firefox 应用了不同的规则:

<script type="text/javascript">
   alert("hello, world&quot;); alert(&quot;XSS");
</script>

这只会显示一个对话框;但引号以转义形式显示。有两个结论:1)" 不被解析为 JavaScript 引号(好),2)它也没有根据 HTML 规则解析(坏)。因此,任何对 html 转义常量的尝试都会创建损坏的数据。

但是,跳过脚本标签中的 html 转义不是一种选择:

<script type="text/javascript">alert("[variable]");</script>
variable: hello, world</script><script>alert("XSS
result: <script type="text/javascript">
        alert("hello, world</script><script>alert("XSS");</script>

由于缺少 ",第一个脚本标签会产生语法错误。但在 Firefox 中,会执行注入的第二个脚本标签。

tl,博士

是否有一种安全的方法可以将不受信任的值写入 JavaScript 常量?这似乎是一团糟,我目前倾向于使用 html 元素(使用 style="dispaly:none")来代替。使用 JSON 的 XMLHttpRequest 调用将是另一种选择。但这两种方法都感觉像是在作弊。

4个回答

另一个有趣的(较旧的)编码库是 OWASP 编码项目(以前是“改革”库) - http://www.owasp.org/index.php/Category:OWASP_Encoding_Project

这在功能上与 Microsoft 的 AntiXSS 1.x 相同(并不罕见——Mike Eddington 编写了很多内部 Microsoft 库,后来成为 AntiXSS,然后是 WPL),但支持Ruby/Rails 之外的大多数常见 Web 语言。

它实现了一种悲观编码方法(编码除已知安全之外的所有内容),并为您提供如下结果:

eval('; --> eval\x28\x27\x3b

评估\u0080 --> 评估\u0080

\u003cscript\u003e。--> \x3cscript\x3e.

如果您的任何安全属性依赖于代码运行——例如关键的 onsubmit 处理程序或 onload 处理程序,则在 onclick 属性中 HTML 转义是不够的。如果攻击者可以嵌入代码点 U+2028 或 U+2029,那么他们可能会导致解析中断,因为不允许在 JS 字符串中进行非转义。

如果您处理的是 XHTML 而不是 HTML,并且您已经定义了自己的 % 实体,那么这些总是一种攻击途径,除非您也转义 % ,但是如果您使用的是 XML,那么差别就小了在脚本元素主体和属性之间。

正如您所注意到的,至少有两种不同的上下文需要不同的转义规则:SCRIPT 标记和包含 Javascript 的属性值。与其试图找到对两者都适用的单一答案,不如为每种情况寻找不同的解决方案。我将主要评论 SCRIPT 标签内的字符串文字。

在 Javascript 中编码字符串常量的一种简单方法是采用不安全字符并将它们转换为 Unicode 转义符:例如a-> \u0061我建议建立一个小的安全字符白名单(az、AZ、0-9),并对其他所有字符进行编码。

更好的是使用标准的、经过严格审查的库来进行转义。我没有具体的建议,但其他人可能有。AntiXSS 有很好的声誉,JavaScriptEncode 看起来很相关。只需确保它适合将插入字符串的特定上下文。

不明显的陷阱:

  • 正如您所注意到</SCRIPT>的,可以终止 SCRIPT 标记,即使它位于带引号的字符串中。这是因为,当浏览器看到打开的标签时,浏览器的 HTML 解析器会在开始使用 Javascript 解析器解析 Javascript 本身之前<SCRIPT>开始寻找关闭</SCRIPT>标签,并且字符串常量中的一个字符串常量可能会过早关闭 SCRIPT 标记。因此,尖括号在 Javascript 字符串文字中以非转义形式出现是不安全的。出于类似的原因,与号也不安全。(感谢 Adam Barth 和 Collin Jackson 教我这个微妙之处。)</SCRIPT>
  • 引号可用于分隔带引号的字符串,因此单引号和双引号不安全。
  • 反斜杠可用于分隔带引号的字符串(想象以 a 结尾\),因此不安全。
  • 如果您使用 JSON,并且在属性名称(而不是值)中包含不受信任的用户输入,事情会变得很棘手。确保引用名称并应用与其他字符串文字相同的规则。此外,可能还需要其他检查(例如,不允许“valueOf”等)。
  • 注意 HTML 页面上使用的字符集。 UTF-7 真的会毁了你的一天我建议您将 + 和 - 视为不安全字符,并确保页面在 Content-Type HTTP 标头或 HTML META 标记中包含显式字符集(以尽量减少浏览器尝试自动检测字符集)。
  • 小心不要双重逃逸。在某些情况下,双重转义会重新引入安全问题。

有用的资源:http ://code.google.com/p/doctype-mirror/wiki/ArticleXSSInJavaScript,http : //code.google.com/p/doctype-mirror/wiki/ArticleXSSInEventHandlers此外,我鼓励您查看Blueprint和 Dan Kaminsky 的 Interpolique,这是解决此类问题的两种创新方法。

如果您使用的是 ASP.NET,我建议您使用 MS 的WPL——AntiXSS 组件提供了一个 .JavaScriptEncode() 方法,这正是您所需要的。
如果您在 JEE 中,我会建议您使用OWASP 的 ESAPI 库- 还有一个 .encodeForJavaScript() 方法(我想我拼写正确,从记忆中......)。
不幸的是,我对 Rails 不够熟悉,无法为此提供解决方案,但也许 OWASP 也有一些东西......(编辑:OWASP 目前正在开发 Ruby 的端口,虽然它还没有发布......)

这些方法都做了什么- 明确编码不被认为是“安全”字符的所有内容。
没有做什么 - 某些“坏”字符的黑名单,需要不断更新,因为它一直被绕过。
根据第一部分,如果有必要,您应该也可以在 Rails 中破解它。我不会推荐它,除非你绝对必须这样做。