在前端开发中,我们经常需要通过JS动态生成HTML内容插入到页面中,比如根据接口返回的数据渲染列表、展示用户提交的内容等。如果这个过程中没有做好安全防护,就很容易被注入恶意脚本,引发XSS攻击。

JS生成HTML常见的XSS风险场景
最常见的风险场景是直接把用户输入或者接口返回的内容,未经处理就通过innerHTML插入到页面中。比如下面这段代码就有明显的安全隐患:
// 恶意用户可能输入 <script>alert('xss')</script>
const userInput = '<script>alert("xss")</script>';
document.getElementById('content').innerHTML = userInput;除了直接插入脚本,还有通过属性注入的风险,比如把用户输入的内容直接拼接到HTML标签的属性中:
const userInput = '" onmouseover="alert('xss')';
document.getElementById('link').innerHTML = `<a href="#" ${userInput}>点击</a>`;避免XSS攻击的核心方法
1. 对输入输出进行转义
如果是要展示纯文本内容,优先对特殊字符进行转义,把<、>、&、"、'等字符转成对应的HTML实体,避免被解析为标签或脚本。可以封装一个通用的转义函数:
function escapeHtml(str) {
if (typeof str !== 'string') return str;
const map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return str.replace(/[&<>"']/g, function(match) {
return map[match];
});
}
// 使用转义后的内容插入
const userInput = '<script>alert("xss")</script>';
document.getElementById('content').innerHTML = escapeHtml(userInput);2. 优先使用安全的DOM API
如果只是要插入文本内容,不要使用innerHTML,而是用textContent,它会自动把内容当作纯文本处理,不会解析HTML标签:
const userInput = '<script>alert("xss")</script>';
// 使用textContent,内容会被当作纯文本展示
document.getElementById('content').textContent = userInput;如果需要创建DOM元素,优先使用document.createElement配合appendChild,而不是直接拼接HTML字符串:
const userInput = '正常文本';
const div = document.createElement('div');
div.textContent = userInput;
document.getElementById('content').appendChild(div);3. 配置内容安全策略(CSP)
可以在页面的HTTP响应头中配置Content-Security-Policy,限制页面可以加载和执行的脚本来源,即使有不慎插入的恶意脚本,也无法执行。比如设置只允许加载同源的脚本:
Content-Security-Policy: script-src 'self';
如果是通过meta标签配置,可以这样写:
<meta http-equiv="Content-Security-Policy" content="script-src 'self'">
4. 富文本场景使用专业的过滤库
如果需要支持用户输入富文本,不要自己写过滤逻辑,优先使用成熟的库比如DOMPurify,它会自动过滤掉恶意的HTML和脚本内容:
// 假设已经引入DOMPurify库
const dirtyHtml = '<script>alert("xss")</script><p>正常内容</p>';
const cleanHtml = DOMPurify.sanitize(dirtyHtml);
document.getElementById('content').innerHTML = cleanHtml;其他注意事项
- 永远不要信任用户输入的内容,所有来自用户、接口的数据都默认是不可信的,必须经过处理再使用
- 避免使用
eval、new Function等可以执行字符串脚本的方法处理用户输入的内容 - 如果必须拼接HTML字符串,除了转义特殊字符,还要严格校验内容的格式,比如URL要校验协议是否合法,避免
javascript:协议的链接
安全是一个持续的过程,除了上述方法,还需要定期做安全审计,及时更新依赖的安全库,才能最大程度降低XSS攻击的风险。