在 Web 安全领域,XSS(跨站脚本攻击)始终位列 OWASP Top 10 的前列。根据恶意脚本的注入方式不同,XSS 通常被分为存储型、反射型和 DOM 型三类。其中,DOM 型 XSS 因其不依赖服务器端渲染、完全在浏览器端触发而显得尤为特殊。很多开发者对存储型和反射型 XSS 已有一定防范意识,却容易忽视 DOM 型 XSS 的隐蔽风险。本文将系统梳理 DOM 型 XSS 的典型触发场景,并给出可落地的安全编码建议,同时也会顺带讨论 SQL 注入防御与 Linux 服务器安全加固的相关要点,帮助开发者建立更完整的 Web 安全防线。
一、什么是 DOM 型 XSS
DOM 型 XSS 是指攻击载荷并未经过服务器端处理,而是由前端 JavaScript 直接读取用户可控的数据源(如 location.hash、location.search、document.referrer 等),并将其不安全地插入到 DOM 中,最终导致脚本执行。与反射型 XSS 的区别在于:反射型 XSS 的恶意代码会出现在服务器响应中,而 DOM 型 XSS 的响应体往往完全正常,恶意代码仅在浏览器端被“组装”出来。
二、常见触发场景
1. 基于 location.hash 的片段导航
单页应用(SPA)常使用 hash 路由。例如:
const name = location.hash.slice(1);
document.getElementById('welcome').innerHTML = '欢迎 ' + name;
攻击者构造 https://example.com/#<img src=x onerror=alert(1)>,页面加载后即可触发脚本执行。由于 hash 内容不会发送到服务器,传统的服务端 WAF 很难拦截。
2. 基于 location.search 的参数读取
const keyword = new URLSearchParams(location.search).get('q');
document.querySelector('.result').innerHTML = keyword;
访问 ?q=<svg onload=alert(document.cookie)> 即可触发。这类场景在搜索结果页、错误提示页中非常普遍。
3. 使用 innerHTML、outerHTML、document.write
任何将字符串直接写入 HTML 解析上下文的操作都可能是危险入口。尤其是 innerHTML,它会将内容按 HTML 解析,事件属性如 onerror、onload 会自动执行。
4. eval、setTimeout、setInterval 等动态执行
const code = location.search.split('=')[1];
eval(decodeURIComponent(code));
这类写法直接将用户输入当作代码执行,属于最危险的模式。类似的还有 new Function()、setTimeout('...') 字符串形式。
5. 第三方库与框架的不安全用法
某些老版本 jQuery 的 $(location.hash)、部分模板引擎的 {{{ }}} 三花括号语法,都会绕过转义直接输出 HTML,从而引入 DOM 型 XSS。
三、前端安全编码指南
1. 优先使用安全的 API
- 使用
textContent代替innerHTML,浏览器会自动将内容视为纯文本。 - 使用
setAttribute设置属性,避免拼接 HTML 字符串。 - 使用
element.append()、createElement()动态创建节点。
2. 必须输出 HTML 时进行严格转义
若业务确实需要富文本,应使用成熟的净化库,如 DOMPurify:
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);
切勿自行编写正则替换,因为 HTML 的解析规则极其复杂,容易绕过。
3. 对 URL 参数进行白名单校验
对于预期为数字、枚举值的参数,直接做类型与范围校验,而不是先接收再过滤。例如:
const page = parseInt(params.get('page'), 10);
if (!Number.isInteger(page) || page < 1) return;
4. 启用内容安全策略(CSP)
CSP 是抵御 XSS 的最后一道防线。建议配置:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';
禁止内联脚本(unsafe-inline)可让大多数 DOM 型 XSS 载荷失效。
5. 避免危险的动态执行
禁用 eval、new Function,改用 JSON.parse 解析数据;定时器传入函数而非字符串。
6. 框架层面的防护
React、Vue 等现代框架默认对插值进行转义,但 dangerouslySetInnerHTML、v-html 等逃生舱仍需谨慎使用,且必须配合净化库。
四、相关安全实践延伸
MySQL 防止 SQL 注入的几种写法
虽然本文聚焦 DOM 型 XSS,但 SQL 注入同样是高频风险。推荐做法包括:
- 参数化查询(预处理语句):
PREPARE stmt FROM 'SELECT * FROM users WHERE id = ?',或使用 PDO、MyBatis 的#{}占位符。 - ORM 框架:如 Hibernate、Sequelize,默认使用参数绑定。
- 最小权限原则:数据库账号仅授予必要权限,禁用
FILE、DROP等高危操作。 - 输入校验辅助:对类型、长度、格式做白名单校验,但不能替代参数化。
Linux 服务器安全加固清单
- 及时更新系统与软件补丁,开启自动安全更新。
- 禁用 root 远程登录,改用密钥认证的普通用户 + sudo。
- 配置防火墙(iptables/firewalld/ufw),仅开放必要端口。
- 使用 Fail2ban 防止暴力破解。
- 关闭不必要的服务与端口,最小化安装。
- 配置日志审计与入侵检测(如 auditd、AIDE)。
- 定期备份并验证恢复流程。
五、总结
DOM 型 XSS 的根源在于“将不可信数据当作代码或 HTML 执行”。防御的核心思路可以归纳为三点:不信任任何客户端输入、优先使用安全 API、以 CSP 作为兜底。前端开发者应养成使用 textContent、净化库和参数校验的习惯,同时结合 SQL 参数化查询与服务器加固,构建纵深防御体系。安全不是一次性的任务,而是贯穿编码、测试、部署全流程的持续实践。
未经允许不得转载:任鹏个人博客 » DOM 型 XSS 的触发场景与安全编码指南


朋友圈点赞图在线生成源码