在JavaScript字符串中,是否需要对字符“<”和“>”进行转义?

17

有时,服务器端将生成字符串以嵌入内联JavaScript代码。例如,如果ASP.NET应生成“UserName”,则如下所示。

<script>
   var username = "<%UserName%>";
</script>

这并不安全,因为用户可以将自己的名称设置为

</script><script>alert('bug')</script></script>

这是一种跨站脚本漏洞(XSS漏洞)。

所以,基本上代码应该是:

<script>
   var username = "<% JavascriptEncode(UserName)%>";
</script>
JavascriptEncode会在"/"、 "'" 和 """之前添加字符"\", 从而使输出的 HTML 看起来像这样。
var username = "</script>alert(\'bug\')</script></script>";
浏览器不会将 "< / script >" 解释为脚本块的结束。因此,可以避免 XSS 攻击。
然而,"<"和">"仍然存在。建议同样转义这两个字符。首先,我认为在此处将"<"更改为"&lt;",将 ">"更改为 "&gt;" 不是一个好主意。而且,我不确定将"<"更改为 "\<",将">"更改为 "\>" 是否能被所有浏览器识别。似乎没有必要进一步对"<"和">"进行编码。
对此有何建议?
谢谢。
3个回答

16

根据你使用的标记语言不同,该问题会有不同的答案。

如果你在使用HTML,则不应该使用实体表示脚本元素,因为它们被标记为包含CDATA。

如果你在使用XHTML,则可以使用显式的CDATA标记将其表示为CDATA,或者可以使用实体表示它们。

如果你在使用XHTML,但是将其作为text/html提供服务,则需要编写符合XHTML规则但仍能与text/html解析器配合使用的内容。这通常意味着使用显式的CDATA标记并在JavaScript中对其进行注释。

<script type="text/javascript">
// <![CDATA[
  …
// ]]>
</script>

我之前写过一点关于这个问题的原因和方法


1
дҪҶжҳҜпјҢCDATAеқ—еҶ…зҡ„]]>дёӯзҡ„>д»Қ然еҝ…йЎ»жӣҝжҚўдёә&gt;гҖӮ еӣ жӯӨпјҢfoo [bar [0]]> 1234еҝ…йЎ»жӣҝжҚўдёәfoo [bar [0]]&lt;1234жҲ–foo [bar [0]]> 1234гҖӮеҗҰеҲҷпјҢCDATAеқ—е°ҶиҝҮж—©е…ій—ӯгҖӮ - Gumbo
由于CDATA将&字符渲染为"&"而不是实体的开始,所以这样做行不通。如果您需要在CDATA中表示字符串"]]>",那么我非常确定您会遇到问题,并且应该一开始就使用实体(在CDATA块之外)。 - Quentin
7
或者只需添加一个空格:foo[bar[0]] > 1234 - 或者如果它是字符串的一部分:'foo[bar[0]]'+'>1234' - 或者只需将所有脚本包含在外部的.js文件中。 - gnarf

14

不应在 HTML 中的 <script> 标签中使用 HTML 实体来转义 <>

  • 应使用 JavaScript 字符串转义规则(用 \ 替换为 \\" 替换为 \"
  • 并且替换所有出现的 </<\/,以防止从 <script> 元素中逃逸出去。

在 XHTML 中,情况更加复杂。

  • 如果将 XHTML 作为 XML 发送(不兼容 IE 的方式)并且不使用 CDATA 块,则需要转义实体,除了 JavaScript 字符串转义之外。
  • 如果将 XHTML 作为 XML 发送并使用 CDATA 块,则不必转义实体,但要用 ]]> 替换为 ]]]]><![CDATA[> 以防止其逃逸(除 JavaScript 字符串转义之外)。
  • 如果将 XHTML 作为 text/html 发送(99% 的人都是这么做的),则必须同时使用 XML CDATA 块、XML CDATA 转义和 HTML 转义。

5
小小的建议:并不是所有</都需要转义(虽然这可能是最简单的解决方法)。只有完整的</script字符串后跟任何空格字符、>/才会结束相应的开放标签。 - Mathias Bynens

2

简单且经济的方法:

<script type="text/javascript">
    var username = "<%= Encode(UserName) %>";
</script>

Encode中的编码方案是将输入的每个字符转换为与JavaScript兼容的关联\xABCD表示。

另一种简单且廉价的方法:

<script type="text/javascript">
    var username = decodeBase64("<%= EncodeBase64(UserName) %>");
</script>

如果你只处理ASCII编码的话。

当然,pst 以严格的方式做到了这一点。


此外,这个解决方案会让你的输出源代码看起来像黑客!+1 - Jørn Schou-Rode

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接