📚 网络安全Kali学习系列 · 模块0-4 编程基础(完结篇)
已完成:模块0-1 Linux系统深度(6篇) ✅ | 模块0-2 计算机网络(4篇) ✅ | 模块0-3 密码学基础(3篇) ✅
14 Python安全编程:socket编程与端口扫描器 ✅
15 Bash脚本与安全自动化:工具链与日志解析 ✅
16 PHP基础与Web漏洞:危险函数与代码审计 ✅
17 JavaScript与前端安全:DOM操作与XSS(当前篇)
下一篇进入模块0-5:Docker/容器基础

JavaScript与前端安全:DOM操作与XSS

难度:基础 | 上一篇你在 PHP 后端审计漏洞成因,本篇视角移到浏览器前端——JavaScript 赋予网页动态能力,同一套 API 也让 XSS 成为 Web 安全史上出现频率最高的漏洞
读完本篇你将能:用 document.getElementById 操作 DOM 节点,区分反射型、存储型和 DOM 型三种 XSS 的触发条件,理解 innerHTML 与 textContent 的安全差异,并用 CSP 和 Trusted Types 构建前端 XSS 防御层——这是模块 2 Web 渗透之前,从前端视角理解漏洞成因的最后一环。
📑 本文目录
01JavaScript与前端安全:浏览器是双刃剑
02JavaScript基础语法:变量、函数与DOM操作
03XSS三种类型:反射型、存储型与DOM型
04DOM型XSS实战:从innerHTML到数据流追踪
05XSS防御体系:输出编码、CSP与Trusted Types
06安全红线与练习

01 JavaScript与前端安全:浏览器是双刃剑

上一篇你在 PHP 后端代码中追踪污点流向——从 $_GET 到 eval()。本篇视角切换到浏览器端。JavaScript 是唯一运行在用户浏览器中的编程语言——它赋予网页动态交互能力,但同一套 DOM API 也让攻击者能够注入并执行恶意脚本。这就是 XSS(Cross-Site Scripting,跨站脚本攻击),OWASP Top 10 中长期排名前三的 Web 安全威胁。

浏览器是一把双刃剑。JavaScript 能读取页面内容、发送网络请求、操作 Cookie——这些能力让 Web 应用强大,但也让攻击者一旦注入脚本就能窃取用户数据。XSS 的本质是:攻击者的输入被浏览器当作代码执行。与 SQL 注入发生在后端数据库不同,XSS 发生在前端浏览器——后端代码再安全,如果前端把用户输入直接写进 HTML,XSS 就成立了。

维度 SQL注入(后端) XSS(前端)
发生位置 数据库引擎 浏览器渲染引擎
注入语言 SQL JavaScript / HTML
攻击者获取 数据库内容 用户Cookie、会话令牌
根本防御 PDO预处理 输出编码 + CSP

JavaScript 当前 ECMAScript 2025(ES2025)规范已于 2026 年 6 月正式发布,所有现代浏览器均已支持 ES2024 全部特性。本篇代码基于浏览器原生 JavaScript,不依赖任何框架——理解原生 DOM API 是审计前端漏洞的前提,React/Vue 等框架的 XSS 问题最终都归结到 DOM 操作的底层行为。

02 JavaScript基础语法:变量、函数与DOM操作

你已经熟悉 Python 和 PHP 的变量概念。JavaScript 变量声明有三个关键字:var(旧版,已不推荐)、let(可变)、const(不可变)。但对安全审计而言,语法不是重点——DOM(Document Object Model)才是。DOM 是浏览器把 HTML 解析成的树形对象结构,JavaScript 通过 DOM API 操作这棵树的节点,改变页面内容、样式和行为。

在 Kali 的 Firefox 浏览器中按 F12 打开开发者工具,切到 Console(控制台)标签页,可以直接输入 JavaScript 代码执行。先看最基本的 DOM 操作——获取元素并修改内容:

JavaScript · 浏览器控制台
1
2
3
4
5
6
7
8
// 获取页面标题元素
const title = document.getElementById('page-title');
// 修改文字内容(安全)
title.textContent = '修改后的标题';
// 修改HTML内容(危险!可能触发XSS)
title.innerHTML = '<b>标题</b>';

第 5 行 textContent 把内容当作纯文本——即使内容包含 <script> 标签也会原样显示,不会执行。第 8 行 innerHTML 把内容当作 HTML 解析—— <b> 会被解析为加粗标签。如果内容来自用户输入,innerHTML 就是 XSS 漏洞的入口。

属性 解析方式 XSS风险 安全等级
textContent 纯文本,不解析HTML 无 安全
innerHTML 解析为HTML标签 高(注入点) 危险
outerHTML 替换整个元素HTML 高(注入点) 危险
💡 小贴士
前端代码审计找 XSS 的第一步:在 JavaScript 源码中搜索 .innerHTML、.outerHTML、document.write()、eval()、setTimeout()(传字符串时)——这五个是 DOM XSS 的"危险汇聚点"(sink)。如果用户可控数据流到了这些 sink 且未经编码,XSS 就成立了。

03 XSS三种类型:反射型、存储型与DOM型

你已经理解了 innerHTML 为什么危险。现在把这个认知扩展到三种 XSS 类型。XSS 按恶意脚本的来源和持久性分为三类,每一类的攻击路径和检测难度不同。安全工程师必须能快速判断目标存在的是哪种类型——这决定了后续的利用方式和防御方案。

类型 数据来源 持久性 触发方式
反射型 URL参数 非持久 用户点击恶意链接
存储型 数据库 持久 用户打开含恶意内容的页面
DOM型 前端JavaScript 非持久 前端数据处理不经过服务器

上一篇 PHP 的 input.php?name=<script>alert(1)</script> 就是反射型 XSS——恶意 payload 在 URL 中,服务器把它拼到 HTML 返回给浏览器。存储型 XSS 更危险:攻击者把恶意脚本提交到评论区、个人资料等存储功能中,每个访问该页面的用户都会中招——不需要点击链接,打开页面就触发。

DOM 型 XSS 是三者中最隐蔽的。它的特点是:恶意数据完全不经过服务器——从 URL 读取到渲染全在前端 JavaScript 中完成。服务器日志中看不到 payload,传统 WAF(Web 应用防火墙)检测不到。看一个最简单的 DOM 型 XSS 代码:

HTML · dom_xss.html
1
2
3
4
5
6
7
8
9
<div id="output"></div>
<script>
// 从URL hash读取用户输入(不经过服务器)
const hash = location.hash.slice(1);
// 漏洞:直接写入innerHTML
document.getElementById('output').innerHTML = hash;
</script>

访问 dom_xss.html#<img src=x onerror=alert(document.cookie)> 时,location.hash 读取 # 后面的内容,直接写入 innerHTML。浏览器解析 <img> 标签,src=x 加载失败触发 onerror 事件执行 alert(document.cookie)——整个攻击过程没有一行请求到达服务器。

攻击者
构造URL
→
服务器
拼接到HTML
→
浏览器
执行脚本
反射型:payload 经过服务器
攻击者
构造URL
→
前端JS
读取hash
→
innerHTML
直接执行
DOM型:payload 不经过服务器

04 DOM型XSS实战:从innerHTML到数据流追踪

上一章你看到了 DOM 型 XSS 的基本原理——location.hash 到 innerHTML。本章用上一篇 PHP 中"污点追踪"的思路,分析一个更真实的前端漏洞场景。前端 JavaScript 的污点追踪链是:用户输入(source)→ 变量传递 → DOM sink。

先写一个搜索页面——用户在搜索框输入关键词,页面显示搜索结果。这是 Web 应用中最常见的功能,也是反射型 XSS 和 DOM 型 XSS 的高发场景:

HTML · search_vuln.html
1
2
3
4
5
6
7
8
9
10
11
12
13
<input type="text" id="search" placeholder="搜索...">
<button onclick="doSearch()">搜索</button>
<div id="result"></div>
<script>
function doSearch() {
  // source: 用户输入
  const keyword = document.getElementById('search').value;
  // sink: innerHTML 直接拼接用户输入
  document.getElementById('result').innerHTML = 
    '<p>搜索: ' + keyword + '</p>';
}
</script>

这段代码的污点追踪链:input.value(source)→ keyword 变量 → 字符串拼接 → innerHTML(sink)。如果用户在搜索框输入 <img src=x onerror=alert('XSS')>,这段 HTML 会被 innerHTML 解析并执行 onerror 中的 JavaScript。

⚠️ 常见错误
element.innerHTML = '<p>' + userInput + '</p>' — 字符串拼接 + innerHTML 是 XSS 的经典组合。用户输入中的 <script> 标签虽然不会被 innerHTML 直接执行(HTML5 规范限制),但 <img onerror>、<svg onload> 等事件处理器能绕过此限制
✓ 正确:用 textContent 或 createTextNode 替代 innerHTML,或在写入前用 encodeURIComponent() 编码

修复方案有两种。最简单的是把 innerHTML 换成 textContent——内容会被当作纯文本,不解析 HTML。如果确实需要渲染 HTML 结构(比如搜索关键词需要高亮),则用 DOM API 安全构建节点:

HTML · search_safe.html(修复版)
1
2
3
4
5
6
7
8
9
10
11
function doSearch() {
  const keyword = document.getElementById('search').value;
  const result = document.getElementById('result');
  // 安全:创建p元素 + textContent写入用户输入
  const p = document.createElement('p');
  p.textContent = '搜索: ' + keyword;
  // 安全替换:先清空再追加
  result.textContent = '';
  result.appendChild(p);
}

修复版用 createElement 创建 <p> 元素,用 textContent 设置内容——用户输入中的 <script> 会被当作纯文本显示,不执行。appendChild 把节点安全插入 DOM 树。这种"先创建节点再设置文本"的模式是前端安全操作 DOM 的标准写法。

💡 小贴士
前端 XSS 审计的"source-sink"分析法:先找 source(用户可控数据入口),常见的有 location.hash、location.search、document.referrer、input.value、localStorage。再找 sink(危险汇聚点),常见的有 innerHTML、eval()、document.write()、setTimeout()。如果 source 和 sink 之间没有编码或过滤,漏洞成立。

05 XSS防御体系:输出编码、CSP与Trusted Types

你已经掌握了用 textContent 替代 innerHTML 的修复方式。但实际项目中不可能逐一替换所有 DOM 操作——大型前端项目有数千处 DOM 写入。业界建立了三层 XSS 防御体系:输出编码(应用层)、CSP 内容安全策略(浏览器层)、Trusted Types(DOM API 层)。

第一层:输出编码。在用户输入写入 HTML 前把特殊字符转义——< 变成 &lt;、> 变成 &gt;,浏览器就不再把它们解析为标签:

JavaScript · encode.js
1
2
3
4
5
6
7
// HTML实体编码函数
function encodeHTML(str) {
  return str
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;');
}

第二层:CSP(Content Security Policy,内容安全策略)。CSP 通过 HTTP 响应头 Content-Security-Policy 告诉浏览器哪些来源的脚本可以执行——即使攻击者注入了 <script> 标签,CSP 也会阻止其执行。在 PHP 中设置 CSP 头:

PHP · csp_header.php
1
2
3
4
5
6
<?php
// 只允许同源脚本 + 禁止内联脚本
header("Content-Security-Policy: "
    . "default-src 'self'; "
    . "script-src 'self' 'nonce-r4nd0m'; "
    . "style-src 'self'");

这个 CSP 策略做了三件事:default-src 'self' 只允许加载同源资源、script-src 'self' 'nonce-r4nd0m' 只允许同源脚本和带特定 nonce 的内联脚本、style-src 'self' 只允许同源样式。攻击者注入的 <script>alert(1)</script> 没有 nonce 值,浏览器拒绝执行。

第三层:Trusted Types。这是 2026 年 2 月正式达到 Baseline 状态的浏览器原生 API——Firefox 在 2026 年 2 月完成支持后,所有主流浏览器均已实现。Trusted Types 从 DOM API 层面根治 DOM 型 XSS:它强制所有 DOM sink(innerHTML、outerHTML 等)只接受"受信任类型"对象,不再接受原始字符串:

JavaScript · trusted_types.js
1
2
3
4
5
6
7
8
9
10
11
12
13
// CSP中启用: require-trusted-types-for 'script'
// 定义安全策略:所有HTML写入必须经过编码
const policy = trustedTypes.createPolicy('escape', {
  createHTML(input) {
    // 在此执行编码/过滤逻辑
    return encodeHTML(input);
  }
});
// 现在innerHTML只接受TrustedHTML对象
document.getElementById('output').innerHTML =
  policy.createHTML(userInput);

Trusted Types 把"开发者需要自觉编码"变成了"浏览器强制编码"——不经过 createPolicy 定义的策略函数,任何字符串都无法写入 innerHTML。这是从"依赖开发者自觉"到"平台强制安全"的范式转变——与 PHP 的 PDO 预处理从根本上防止 SQL 注入是同一种思路。

06 安全红线与练习

本篇所有 XSS 漏洞复现必须在本地环境进行——自己电脑上的浏览器、本机启动的 PHP 服务器、DVWA 靶场。XSS 的 payload <script>alert(document.cookie)</script> 在真实网站上意味着窃取用户 Cookie——如果在他人网站上注入这段代码,即使只是弹窗测试,也已触犯《刑法》第 285 条。合法练习方式:本机 127.0.0.1、DVWA 靶场、PortSwigger Web Academy 免费实验室。

📖 知识回顾
DOM操作 innerHTML vs textContent 反射型XSS 存储型XSS DOM型XSS source-sink分析 输出编码 CSP策略 Trusted Types
✏️ 动手练习
🟢 基础验证
在 Kali 浏览器中新建一个 HTML 文件,创建一个输入框和按钮,点击按钮后用 textContent 把输入内容显示在页面上。然后在输入框中输入 <script>alert(1)</script>,验证是否会执行。再把 textContent 换成 innerHTML,输入相同内容观察差异。
🟡 组合应用
修改第四章的搜索页面漏洞版 search_vuln.html,让它从 location.search(URL 参数 ?q=)读取搜索关键词而非输入框。然后构造一个包含 onerror 事件的 XSS payload URL,在浏览器中验证触发。最后用 encodeURIComponent() 编码修复。这是模块 2 Burp Suite 拦截 URL 参数修改的预热练习。
🔴 开放挑战
写一个"留言板"页面,同时包含存储型 XSS 漏洞(用 localStorage 存储留言,读取后用 innerHTML 渲染)和 DOM 型 XSS 漏洞(从 URL hash 读取高亮关键词写入 innerHTML)。然后审计你自己的代码,画出两条污点追踪链(source → sink),并分别用 textContent 和 createTextNode 修复。提示:搜索"DOMPurify"了解业界标准的 HTML 消毒库。
模块0-4 编程基础 · 完结总结
模块 0-4 用四篇文章覆盖了安全工程师必备的四种编程语言:
14Python — socket 编程与多线程端口扫描器
15Bash — 管道、文本处理与安全工具链自动化
16PHP — 危险函数、SQL 注入与文件上传审计
17JavaScript — DOM 操作与三种 XSS 类型
这四种语言的共同主题是"污点追踪"——从用户可控输入出发,追踪数据流直到危险汇聚点。下一模块将进入 Docker 容器化——用 Docker 部署 DVWA 靶场,把这些代码层面的漏洞知识放到真实的渗透环境中验证。
下篇预告 · 进入模块0-5
模块0-5 Docker/容器基础
将学习 Docker 镜像与容器概念、Dockerfile 编写、docker-compose 编排,并用 Docker 在云服务器上部署 DVWA 靶场——为模块 2 Web 渗透搭建真实漏洞环境
关注公众号 · 持续获取安全学习系列