XSS攻击全称为跨站脚本攻击,是Web应用中最常见的安全漏洞之一,攻击者通过在页面中注入恶意JavaScript脚本,当用户访问页面时脚本会自动执行,进而窃取用户Cookie、会话令牌等敏感信息,或者篡改页面内容、跳转恶意链接。要编写安全的JavaScript代码,首先需要了解XSS攻击的三种主要类型,再针对性地采取防护措施。

XSS攻击的常见类型
存储型XSS
存储型XSS的恶意脚本会被永久存储在服务器端,比如论坛的评论区、用户资料页等位置。当其他用户访问包含恶意脚本的页面时,脚本会从服务器加载并执行,影响范围通常比较广。
反射型XSS
反射型XSS的恶意脚本不会存储在服务器,而是通过URL参数等方式传递,服务器接收到参数后直接返回到页面中。攻击者通常会构造包含恶意脚本的钓鱼链接,诱导用户点击触发攻击。
DOM型XSS
DOM型XSS的攻击过程不涉及服务器端,完全是前端JavaScript操作DOM时未做安全处理导致的。恶意脚本通过修改页面的DOM结构执行,比如使用innerHTML直接插入未过滤的用户输入内容。
编写安全JavaScript代码的核心防护措施
1. 严格的输入验证与过滤
对所有用户输入的内容进行验证,只允许符合预期格式的内容通过,同时过滤掉可能的恶意脚本标签和属性。比如用户名只允许字母、数字和下划线,评论内容过滤掉script、iframe等危险标签。
以下是一个简单的输入过滤函数示例,用于过滤常见的危险标签:
/**
* 过滤用户输入中的危险HTML标签
* @param {string} input - 用户输入的原始内容
* @returns {string} 过滤后的安全内容
*/
function filterDangerousTags(input) {
if (typeof input !== 'string') {
return '';
}
// 替换script标签,包括大小写变体
let filtered = input.replace(/<script[sS]*?>[sS]*?</script>/gi, '');
// 过滤iframe、object、embed等危险标签
filtered = filtered.replace(/<(iframe|object|embed|svg)[sS]*?>[sS]*?</1>/gi, '');
// 过滤on开头的事件属性,比如onclick、onload
filtered = filtered.replace(/s+onw+s*=s*["'][^"']*["']/gi, '');
return filtered;
}
// 使用示例
const userInput = '<script>alert("xss")</script><p>正常内容</p>';
const safeInput = filterDangerousTags(userInput);
console.log(safeInput); // 输出 <p>正常内容</p>
2. 输出时正确编码
当需要将用户输入的内容输出到页面时,要根据输出的上下文进行对应的编码,避免浏览器将内容解析为可执行的脚本。常见的输出场景和对应的编码方式如下:
| 输出场景 | 编码方式 | 说明 |
|---|---|---|
| HTML正文 | HTML实体编码 | 将<、>、&、"等字符转义为对应的实体,比如<转义为< |
| HTML属性 | 属性值编码 | 除了HTML实体编码外,还要确保属性值用引号包裹,避免属性值被截断注入 |
| JavaScript上下文 | JS编码 | 将用户输入的内容转义为合法的JS字符串,避免闭合引号注入脚本 |
| URL上下文 | URL编码 | 使用encodeURIComponent对参数进行编码,避免注入恶意协议或路径 |
以下是一个HTML实体编码的实现示例:
/**
* HTML实体编码,防止内容被解析为HTML标签
* @param {string} str - 需要编码的字符串
* @returns {string} 编码后的字符串
*/
function encodeHTML(str) {
if (typeof str !== 'string') {
return '';
}
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// 使用示例
const unsafeContent = '<img src="x" onerror="alert(1)">';
const encodedContent = encodeHTML(unsafeContent);
// 输出到页面时,encodedContent会被显示为普通文本,不会执行脚本
document.getElementById('content').textContent = encodedContent;
3. 避免不安全的DOM操作
前端操作DOM时,尽量避免使用innerHTML、outerHTML等会解析HTML字符串的属性,优先使用textContent、innerText来插入文本内容,这两个属性只会将内容作为纯文本处理,不会执行其中的脚本。
如果必须使用innerHTML,一定要先对插入的内容进行编码处理,示例:
// 不安全的写法,直接插入用户输入
const userComment = '<script>stealCookie()</script>';
document.getElementById('comment').innerHTML = userComment; // 会执行恶意脚本
// 安全的写法,先编码再插入
const safeComment = encodeHTML(userComment);
document.getElementById('comment').innerHTML = safeComment; // 只会显示文本,不会执行脚本
4. 使用内容安全策略(CSP)
内容安全策略是服务器端通过响应头设置的一种安全机制,可以限制页面可以加载的资源来源,禁止执行内联脚本和不安全的脚本源,从根源上降低XSS攻击的影响。常见的CSP配置如下:
// 服务器端设置响应头示例(Node.js Express框架)
const express = require('express');
const app = express();
app.use((req, res, next) => {
// 只允许从同源加载脚本,禁止内联脚本,禁止eval执行
res.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:");
next();
});
CSP的常用指令说明:
- default-src:设置所有资源的默认加载源
- script-src:设置脚本的加载源,设置为
'self'表示只允许同源脚本,'unsafe-inline'允许内联脚本(不建议开启) - style-src:设置样式表的加载源
- img-src:设置图片的加载源
5. 其他辅助防护措施
- 设置Cookie的
HttpOnly属性,让JavaScript无法读取Cookie,即使发生XSS攻击,攻击者也无法窃取Cookie内容 - 尽量使用前端框架(如React、Vue)开发,这些框架内置了XSS防护机制,默认会对插入的内容进行编码处理
- 避免使用
eval()、new Function()等可以执行字符串脚本的方法,防止恶意字符串被执行 - 对用户输入的URL进行校验,只允许http、https协议的链接,禁止javascript:伪协议
总结
防止XSS攻击需要从输入、输出、DOM操作、服务器配置等多个层面共同入手,没有单一的防护方法可以完全杜绝XSS风险。开发者在编写JavaScript代码时,要始终保持安全意识,对所有用户输入的内容持不信任态度,结合输入过滤、输出编码、CSP策略等多种手段,才能有效降低XSS攻击的发生概率,保障应用和用户数据的安全。
XSS攻击JavaScript安全输入过滤输出编码CSP策略修改时间:2026-06-10 13:12:28