跨站点脚本 (XSS) 是一种攻击类型,攻击者会将客户端 JavaScript 注入您的网站,从而在用户的浏览器可信环境中运行。
防止 XSS 攻击最干净的方法是在注入点对不受信任的数据进行转义。这意味着在将数据实际注入 HTML 的位置进行转义。
使用 <%= %>
对数据进行 HTML 编码
<h3 is="welcome-msg">Hello <%= me.username %>!</h3>
<h4><%= owner.username %>'s projects:</h4>
<ul><% _.each(projects, function (project) { %>
<li>
<a href="/<%= owner.username %>/<%= project.slug %>"><%= project.friendlyName %></a>
</li>
<% }); %></ul>
使用 exposeLocalsToBrowser
部分安全地将部分或所有视图局部变量暴露给客户端 JavaScript
<%- exposeLocalsToBrowser(); %>
<script>
console.log(window.SAILS_LOCALS);
// {
// me: {
// username: 'eleven',
// memberSince: '1982-08-01T05:00:00.000Z'
// },
// owner: {
// username: 'joyce',
// memberSince: '1987-11-03T05:00:00.000Z'
// },
// projects: [
// {
// slug: 'my-neat-stuff-n-things',
// friendlyName: 'My neat stuff & things',
// description: 'Yet another project.'
// },
// {
// slug: 'kind-of-neat-stuff-but-not-that-great',
// friendlyName: 'Kind of neat stuff, but not that great...',
// description: 'I am so sick and tired of these project. <script>alert(\'attack\');</script>'
// }
// ],
// _csrf: 'oon95Uac-wKfWQKC5pHx1rP3HsiN9tjqGMyE'
// }
</script>
请注意,当您使用此策略时,视图局部变量中的字符串在暴露给客户端 JavaScript 后将不再进行 HTML 解码。这是因为您需要在将它们粘贴到 DOM 中时再次对其进行转义。如果您始终在注入点进行转义,则这些内容将更容易跟踪。这样,您就可以安全地转义从客户端 JavaScript 注入 DOM 的任何字符串。(下面将详细介绍。)
许多 XSS 防御措施与您在客户端代码中执行的操作有关。以下是一些示例
使用 <%- %>
对数据进行 HTML 编码
<div data-template-id="welcome-box">
<h3 is="welcome-msg">Hello <%- me.username %>!</h3>
</div>
使用类似 $(...).text()
的方法对数据进行 HTML 编码
var $welcomeMsg = $('#signup').find('[is="welcome-msg"]');
welcomeMsg.text('Hello, '+window.SAILS_LOCALS.me.username+'!');
// Avoid using `$(...).html()` to inject untrusted data.
// Even if you know an XSS is not possible under particular circumstances,
// accidental escaping issues can cause really, really annoying client-side bugs.
您可能已经意识到,上面的示例假设您使用的是 jQuery,但无论您使用哪种前端库,相同的概念都适用。
- 上面的示例假设您使用默认视图引擎 (EJS) 和来自默认资产管道中的客户端 JST/Lodash 模板。