防范措施
我们可以自行封装防范方法,根据项目需求定制标准;也可以借助成熟工具库,更便捷高效。以下整理了几种常用方案的用法。
1. layui util
Layui 的 util.escape() 是核心的 XSS 防护手段,它会将 HTML 中的特殊字符转换为对应的实体,阻止浏览器解析执行恶意脚本,从根源上拦截大部分反射型和存储型攻击。
核心转义的特殊字符
该方法针对 HTML 中最具危险性的字符进行转义,规则如下:
| 原始字符 | 转义后 | 说明 |
|---|---|---|
< | < | 标签开始标识 |
> | > | 标签结束标识 |
" | " | 属性值包裹 |
' | ' | 属性值包裹 |
& | & | 实体起始标识 |
这些字符常被用于注入脚本(如 <script>alert('XSS')</script>),转义后变为纯文本,无法执行。
示例
layui.use('util', function(){
var util = layui.util;
// 模拟用户输入的恶意内容
var maliciousContent = '<script>alert("XSS 攻击");</script><a href="javascript:evil()">恶意链接</a>';
// 转义处理
var safeContent = util.escape(maliciousContent);
console.log(safeContent);
// 插入页面时仅显示文本
document.getElementById('content').innerText = safeContent;
});
2. js-xss 库
js-xss 能过滤 HTML 字符串、移除危险标签或属性,确保输出的 HTML 安全可渲染。
安装
Node.js 环境
# npm
npm install xss --save
# yarn
yarn add xss
浏览器环境
直接引入 CDN 或本地文件:
<!-- CDN -->
<script src="https://cdn.jsdelivr.net/npm/xss/dist/xss.min.js"></script>
<!-- 本地 -->
<script src="path/to/xss.min.js"></script>
核心 API 基础使用
核心函数为 xss(),传入待过滤字符串即可返回安全的 HTML。
基础过滤(默认规则)
默认会移除 <script>、<iframe> 等危险标签及 onclick 等危险属性,保留常规标签。
// Node.js 环境
const xss = require('xss');
// 浏览器环境直接使用全局变量 xss
const dangerousHtml = `
<div onclick="alert('xss')">点击我</div>
<script>stealData()</script>
<img src="x" onerror="alert(1)">
`;
const safeHtml = xss(dangerousHtml);
console.log(safeHtml);
// 输出:<div>点击我</div><img src="x">
自定义过滤规则
通过配置选项满足个性化需求,例如允许特定标签或属性。
(1) 允许特定标签
const safeHtml = xss(dangerousHtml, {
whiteList: {
div: [], // 允许 div,无属性
p: ['class'], // 允许 class
img: ['src', 'alt'] // 允许 src 和 alt
}
});
(2) 允许特定属性
const html = '<div onclick="alert(1)">内容</div>';
const safeHtml = xss(html, {
whiteList: {
div: ['class', 'data-id'] // 移除 onclick
}
});
console.log(safeHtml); // <div>内容</div>
(3) 自定义标签处理
利用 onTag 钩子控制逻辑:
const safeHtml = xss(dangerousHtml, {
onTag: function(tag, html, options) {
if (tag === 'h1') return ''; // 禁止 h1
return undefined; // 其他按默认处理
}
});
(4) 自定义属性处理
利用 onTagAttr 钩子过滤属性值:
const html = '<a href="javascript:alert(1)">链接</a>';
const safeHtml = xss(html, {
onTagAttr: function(tag, name, value, isWhiteAttr) {
if (tag === 'a' && name === 'href') {
if (value.startsWith('javascript:')) {
return 'href="#invalid"';
}
}
return isWhiteAttr ? `${name}="${xss.escapeAttrValue(value)}"` : '';
}
});
console.log(safeHtml); // <a href="#invalid">链接</a>
(5) 转义特定字符
默认已转义 <、> 等,也可自定义:
const safeHtml = xss('<p>hello & world</p>', {
escapeHtml: function(html) {
return html.replace(/&/g, '&').replace(/</g, '<');
}
});
console.log(safeHtml); // <p>hello & world</p>
常见场景示例
1. 过滤用户评论
const userComment = `
<p>我的评论</p>
<script>偷取 cookie</script>
<img src=x onerror="alert('xss')">
`;
const safeComment = xss(userComment, {
whiteList: {
p: ['class'],
img: ['src', 'alt']
}
});
document.getElementById('comment').innerHTML = safeComment;
2. 富文本编辑器内容
const richTextWhiteList = {
h1: ['class'], h2: ['class'], p: ['class', 'style'],
a: ['href', 'target', 'class'],
img: ['src', 'alt', 'class', 'width', 'height'],
strong: [], em: []
};
const richText = '<p>富文本<a href="javascript:alert(1)">危险链接</a></p>';
const safeRichText = xss(richText, {
whiteList: richTextWhiteList,
onTagAttr: function(tag, name, value) {
if (tag === 'p' && name === 'style') {
if (/^color:\s*[a-zA-Z0-9#]+;?$/.test(value)) {
return `style="${value}"`;
}
return '';
}
if (tag === 'a' && name === 'href') {
if (value.startsWith('javascript:')) {
return 'href="#"';
}
return `href="${value}"`;
}
return `${name}="${value}"`;
}
});
注意事项
- 不要完全依赖默认规则:根据业务定制白名单,避免放行不必要的标签。
- 富文本处理需谨慎:精细化配置白名单和属性过滤。
- 服务端 + 客户端双重过滤:客户端提升体验,服务端是最后一道防线(防止绕过)。
- 特殊场景例外:如需允许部分安全脚本,必须严格校验。
更多配置
完整配置项参考官方文档,核心包括 whiteList、onTag、onTagAttr、escapeHtml 等。灵活配置可适配绝大多数场景。
前端虽有 XSS 防护,但主要还需后端配合。不要仅依赖「前端过滤」:攻击者可通过 Postman 等工具直接请求接口,后端必须过滤。

