Django的escapejs过滤器与XSS

6 投票
1 回答
9188 浏览
提问于 2025-04-18 04:32

我想用Django的模板语言来处理一些JavaScript变量。我的情况是这样的,foo是一个用户定义的数据字符串(也就是不太可信的数据),我想把它转换成JavaScript字符串。

<!doctype html>
<html>
    <head>
        <script>
            bar = '{{ foo|escapejs }}';        
        </script>
    </head>
    <body>
    </body>
</html>

如果我没理解错的话,按照Django的文档,像这样使用escapejs会有XSS攻击的风险。

我想到了一个可能的解决办法,就是使用HTML5的data-*属性,像这样。

<!doctype html>
<html>
    <head>
        <script>
            window.onload = function () {
                bar = document.getElementById('data').getAttribute('data-bar');
            };
        </script>
    </head>
    <body>
        <div id="data" style="display:none;" data-bar="{{ foo }}"></div>
    </body>
</html>

不过,我在想有没有更简单或者更标准的方法来做到这一点。

1 个回答

7

escapejs 的输出在把 JavaScript 放在 HTML 文本里或者放在 HTML 属性值里时是安全的。但如果是放在没有引号的 HTML 属性值里,就不安全了(其实 escape 对于没有引号的 HTML 属性也不安全,所以无论如何都要加引号)。

这样做是可以的,因为它会把所有 HTML 特殊字符转换成 JavaScript 字符串的格式 \u,这些格式里不包含 HTML 特殊字符。可以查看 django.utils.html 里的 _base_js_escapes。它还会把输出标记为“安全”,所以你希望这不是个谎言。

至于这是否应该是安全的,以及未来的 Django 版本是否能保证它一直安全,这点不太清楚,因为你提到的文档并没有说明。它可能只是想说,这种转义方式不适合普通的 HTML:虽然现在的实现并不是说对普通 HTML 的转义不安全,但你肯定会得到错误的输出,里面会有多余的反斜杠。你觉得自己运气好吗?

我想到了一个可能的解决方案,使用 HTML5 的 data-* 属性,像这样。

无论如何,我都会这样做。把 JavaScript 嵌入到模板里很容易出错,而且直接在页面里写 JavaScript 有点乱,未来也不方便使用内容安全策略。

更好的做法是把所有页面数据放在 HTML 属性里,使用同样的安全 HTML 自动转义,然后让 JavaScript 从 DOM 中获取这些数据。当然,如果你想包含结构化数据而不仅仅是字符串,可以把它们 JSON 编码。

(不过我不会去弄一个手动的隐形 div……你可以把属性加到 <body> 或者其他与数据相关的元素上。)

撰写回答