DOM 型 XSS 的触发场景与安全编码指南

在 Web 安全领域,XSS(跨站脚本攻击)始终位列 OWASP Top 10 的前列。根据恶意脚本的注入方式不同,XSS 通常被分为存储型、反射型和 DOM 型三类。其中,DOM 型 XSS 因其不依赖服务器端渲染、完全在浏览器端触发而显得尤为特殊。很多开发者对存储型和反射型 XSS 已有一定防范意识,却容易忽视 DOM 型 XSS 的隐蔽风险。本文将系统梳理 DOM 型 XSS 的典型触发场景,并给出可落地的安全编码建议,同时也会顺带讨论 SQL 注入防御与 Linux 服务器安全加固的相关要点,帮助开发者建立更完整的 Web 安全防线。

一、什么是 DOM 型 XSS

DOM 型 XSS 是指攻击载荷并未经过服务器端处理,而是由前端 JavaScript 直接读取用户可控的数据源(如 location.hashlocation.searchdocument.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 解析,事件属性如 onerroronload 会自动执行。

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. 避免危险的动态执行

禁用 evalnew Function,改用 JSON.parse 解析数据;定时器传入函数而非字符串。

6. 框架层面的防护

React、Vue 等现代框架默认对插值进行转义,但 dangerouslySetInnerHTMLv-html 等逃生舱仍需谨慎使用,且必须配合净化库。

四、相关安全实践延伸

MySQL 防止 SQL 注入的几种写法

虽然本文聚焦 DOM 型 XSS,但 SQL 注入同样是高频风险。推荐做法包括:

  1. 参数化查询(预处理语句)PREPARE stmt FROM 'SELECT * FROM users WHERE id = ?',或使用 PDO、MyBatis 的 #{} 占位符。
  2. ORM 框架:如 Hibernate、Sequelize,默认使用参数绑定。
  3. 最小权限原则:数据库账号仅授予必要权限,禁用 FILEDROP 等高危操作。
  4. 输入校验辅助:对类型、长度、格式做白名单校验,但不能替代参数化。

Linux 服务器安全加固清单

  1. 及时更新系统与软件补丁,开启自动安全更新。
  2. 禁用 root 远程登录,改用密钥认证的普通用户 + sudo。
  3. 配置防火墙(iptables/firewalld/ufw),仅开放必要端口。
  4. 使用 Fail2ban 防止暴力破解。
  5. 关闭不必要的服务与端口,最小化安装。
  6. 配置日志审计与入侵检测(如 auditd、AIDE)。
  7. 定期备份并验证恢复流程。

五、总结

DOM 型 XSS 的根源在于“将不可信数据当作代码或 HTML 执行”。防御的核心思路可以归纳为三点:不信任任何客户端输入、优先使用安全 API、以 CSP 作为兜底。前端开发者应养成使用 textContent、净化库和参数校验的习惯,同时结合 SQL 参数化查询与服务器加固,构建纵深防御体系。安全不是一次性的任务,而是贯穿编码、测试、部署全流程的持续实践。

未经允许不得转载:任鹏个人博客 » DOM 型 XSS 的触发场景与安全编码指南

赞 (0) 打赏

评论 0

取消
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏