在 Python 3.6+ 中,是否有一种简洁的方法来对 JavaScript 上下文的输出进行编码?
这意味着,如果我从任何未经处理的输入字符串开始,对其进行正确编码,然后用它替换下面的
VALUE
,则网页中的所有 XSS 攻击都将被阻止。输入无法突破 JavaScript 字符串,也无法突破 HTML。
<!DOCTYPE html>
<html>
<head>
<script>
var a = 'VALUE';
</script>
</head>
</html>
我上面提供的链接是官方的 OWASP 预防 XSS 备忘单,其中规定所有非字母数字字符必须进行十六进制转义。他们在文章中提供了 Java 实现,但除了 this 之外,我一直找不到 Python 实现,它自 2010 年以来就没有更新过。所以我写了自己的:
import curses.ascii
def as_js_in_html(value):
result = ''
for char in value:
if curses.ascii.isalnum(char):
result += char
else:
char_hex = format(ord(char), 'x')
if len(char_hex) <= 2:
result += '\\x' + char_hex.rjust(2, '0')
elif len(char_hex) <= 6:
result += '\\u{' + char_hex + '}'
return result
有更好的办法吗?
一种解决方案是使用 CDATA 部分,它在 XML 中有效。 CDATA 部分使用
<![CDATA[
进行声明,一直持续到 ]]>
,并保护输入不超出 HTML。这可以简化您必须自己编写的代码。这里,VALUE
是XSS攻击,它不起作用,因为输入在CDATA内,所以它无法突破HTML:
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
<head>
<script>
// <![CDATA[
var a = "</script><script>alert('XSS');</script>";
console.log(a);
// ]]>
</script>
</head>
</html>
正如 MDN 文档中所解释的:
“当在 CDATA 部分内时,符号
<
和 &
不需要像通常那样转义”(参见链接)。这意味着我们不再需要对输入进行 HTML 转义。
“[CDATA 部分] 仅适用于 XML,不适用于 HTML 文档(因为 HTML 文档不支持 CDATA 部分)”(参见链接)。
XML 文档必须使用
Content-Type: application/xhtml+xml
提供(参见链接)。否则,“浏览器使用 HTML 解析器而不是 XML 解析器来解析这些文档。”
注意事项:
您必须使用
Content-Type: application/xhtml+xml
提供 XML HTML 文档,否则这将不起作用。
json.dumps
的内容来防止换行符和引号从 JavaScript 变量中转义。
任何 CDATA 关闭序列
]]>
都必须从未经消毒的输入中删除或替换。
CDATA 部分在标准中之前已经过时,然后由于网络损坏又重新添加了。所以这种技术可能已经过时了。如果您有任何关于这是否被视为良好实践的信息,请发表评论。