关于 Web 漏洞原理与利用:2. XSS(跨站脚本攻击)

一、原理:

用户输入未过滤被执行

攻击者输入的内容,如果没有被正确处理(过滤/转义),被网页原样输出到浏览器中,那么这些内容就可能会被浏览器当成代码执行,这就是 XSS(跨站脚本攻击)。

三个关键部分

1)用户输入

用户可以控制的数据(攻击者当然也就可以),比如:

  • URL 参数:?name=张三

  • 表单内容:用户名、评论内容

  • Cookie 值、Referer

  • 上传的 HTML 内容(富文本)

2)未过滤

服务器或者前端在把这些用户输入写进网页时

  • 没有去掉危险标签,如

    最终页面:

    欢迎你,

    浏览器看到

    其他用户访问该页面时,浏览器执行这段脚本,攻击者就能拿到他们的 cookie,实现会话劫持。

    5. 实验

    建立  XSS测试.html  文件测试:

    
    
    XSS 测试
    
      

    XSS测试页面

    方法一:用「Live Server」启动本地网页,访问 http://localhost:5500/XSS测试.html?input=...

    • VS Code 安装并启用 Live Server 插件。

    • 右键 HTML 文件 → 选择 Open with Live Server

    • 浏览器打开的地址会变成 http://127.0.0.1:5500/XSS测试.html?input=...,这样就支持 URL 参数。

    •  JS 代码能正确读取参数并执行。

    访问:

    http://127.0.0.1:5500/XSS测试.html?input=

    会看到一个弹窗,这就是 XSS 原理最基本的演示。

    方法二:使用本地简单 HTTP 服务器(Python)

    如果有 Python,打开终端,进入 HTML 文件目录,运行:

    python -m http.server 8000
    

    然后浏览器打开:

    http://localhost:8000/XSS测试.html?input=

    一样可以看到弹窗

    6. 防止“未过滤被执行”

    核心原则:用户输入是数据,永远不能当代码看待

    常见防御:

    • 输出前进行 HTML 转义:如 <>"

    • 不拼接 HTML,使用模板引擎的自动转义功能(如 React、Vue 默认安全)

    • 严格 CSP(内容安全策略)

    • 前后端联动做白名单过滤

    总结

    元素 内容
    用户输入 攻击者可以控制的内容
    未过滤 没有进行转义、校验、过滤
    被执行 浏览器把它当代码运行了

    原理核心:数据变代码,浏览器帮攻击者执行了它。


    二、分类:

    反射型XSS

    反射型 XSS(Reflected XSS)是指攻击者构造一个包含恶意脚本的 URL,当用户点击这个链接时,浏览器请求该 URL,服务端将 URL 中的参数**“原样返回”到页面中**,恶意脚本就会被浏览器执行。

    反射:攻击内容从请求发出后,被原样“反射”回响应中。

    攻击流程

    • 攻击者构造恶意 URL,注入脚本

    • 用户点击 URL,向服务器发起请求

    • 服务器把用户提交的参数直接输出到页面(未过滤)

    • 浏览器接收到返回页面时,直接执行了注入的脚本

    1. 示例

    服务端代码(假设):

    # Flask 示例
    @app.route('/hello')
    def hello():
        name = request.args.get('name')
        return f"

    Hello, {name}

    "

    用户访问链接:

    http://example.com/hello?name=张三
    

    返回页面:

    Hello, 张三

    攻击者构造链接:

    http://example.com/hello?name=
    

    返回页面变成了:

    Hello,

    此时浏览器直接执行了

    普通用户访问时:

    服务器返回页面内容:

    浏览器立刻执行脚本,攻击者成功获取用户 cookie。

    2. 常见注入位置

    • 用户名 / 昵称

    • 评论 / 留言板

    • 论坛帖子 / 私信内容

    • 富文本编辑器内容(不设白名单)

    • 上传的 .html 文件(静态页面)

    3. 危害有多严重?

    • 窃取所有访问者的 cookie → 劫持账户

    • 注入恶意 JS 窃取密码、银行卡号

    • 引导用户跳转钓鱼页面

    • 自动转发攻击内容(蠕虫式 XSS)

    • 管理后台如果中招,可能导致网站被完全控制(如植入木马、篡改内容)

    4. 防御方法

    1)输出编码(核心)

    在展示评论、昵称、文章等用户内容时,一定要做 HTML 实体编码

    • <<

    • >>

    • ""

    一定是在“展示环节编码”,而不是“存储环节过滤”。

    2)富文本要严格白名单

    如果是富文本编辑器(如 KindEditor、TinyMCE)允许部分 HTML,要使用如:

    • DOMPurify 进行白名单清洗

    • 只允许安全标签(如 , , ),禁止

      访问链接模拟存储结果:

      ?comment=
      

      用户访问页面,看到评论区立即弹窗。

      然后:

      • 打开页面 → 按 F12 打开控制台

      • 点击上方的「Application」标签页

      • 左侧导航栏里点「**Local Storage → http://127.0.0.1:5500**」

      可以看到 存储了 评论数据或者攻击者提交的恶意脚本。

      总结

      项目 内容
      类型 存储型 XSS(Stored XSS)
      攻击持久性 被存储在数据库
      用户触发条件 自动触发,无需点击
      常见注入点 评论、帖子、用户名、富文本
      危害程度 高,可能影响所有用户甚至管理后台
      防御措施 输出转义、富文本清洗、CSP、安全编码规范

      =======================================

      DOM型XSS

      DOM 型 XSS(DOM-based XSS)是指漏洞存在于前端 JavaScript 代码中,浏览器在解析页面并运行 JS 时,因为未对用户输入做处理,导致恶意代码被执行。

      它完全发生在浏览器端,服务端甚至不知道有攻击发生。

      1. 举例

      
      

      欢迎你,

      用户访问链接:

      http://example.com/#
      

      渲染后页面变为:

      欢迎你,

      加载失败,触发 onerror,弹出 XSS。

      2. 和其他 XSS 的区别

      特征 反射型 / 存储型 XSS DOM 型 XSS
      漏洞位置 服务端输出(HTML 模板) 前端 JS 代码(DOM 操作)
      攻击执行位置 响应内容中 浏览器执行 JS 时
      服务端是否参与 参与 完全不参与
      检测难度 相对容易 更隐蔽更难检测
      常见位置 URL 参数 / 表单 / 评论区 location, document, innerHTML, eval, 等

      3. 攻击流程(四步)

      • 攻击者构造一个 URL,包含恶意代码在 URL 参数、锚点等位置

      • 用户点击链接后加载页面

      • 前端 JS 从 location.hash / search / document.cookie 等读取数据

      • 这些数据被拼接到 DOM 中或被 eval() 执行 → 触发脚本

      4. 危险写法

      危险代码 原因
      element.innerHTML = userData 会执行嵌套脚本标签
      eval(userData) 直接执行任意 JS 表达式
      location.href = userInput 可用于跳转攻击
      document.write(userData) 也会执行脚本

      漏洞点关键来源

      • location.href, location.search, location.hash

      • document.referrer

      • document.cookie

      • window.name

      5. 示例:搜索框拼接 XSS

      示例页面代码:

      
      
      
        
        DOM型XSS演示
      
      
        
        
      
        

      访问链接:

      http://127.0.0.1:5500/DOMxss.html?kw=

      结果页面:

      您搜索了:
      

      浏览器执行 XSS。

      6. 防御方法

      1)不使用 innerHTML 显示用户数据

      • textContent / innerText 替代

      el.textContent = userInput;  // 安全
      

      2)所有输入都做白名单验证

      • URL 参数、cookie、hash 等都要校验格式

      • 只允许字母、数字、下划线等,避免注入 HTML

      3)使用 DOMPurify 清洗危险 HTML

      • 前端引入 DOMPurify

      const clean = DOMPurify.sanitize(userInput);
      element.innerHTML = clean;

      4)尽量避免使用 eval()setTimeout(str) 等执行字符串

      5)配置 CSP(内容安全策略)

      Content-Security-Policy: script-src 'self'; object-src 'none'
      • 禁止内联脚本执行,有效拦截部分 DOM XSS

      7. 安全开发

      • 前端读取任何来源的数据(URL, cookie, localStorage)都要当做不可信

      • 不信任用户、URL、外部 API 的任何内容

      • 安全框架如 React、Vue 默认用 Virtual DOM,能减少 XSS,但不是万无一失

      总结

      项目 内容
      类型 DOM 型 XSS(前端型)
      漏洞位置 前端 JS 代码
      攻击点 innerHTML, eval, location.hash
      危害 窃取信息、钓鱼跳转、Cookie 劫持
      特点 服务端完全无感知,检测困难
      防御方法 替换危险 API、严格校验、DOMPurify、CSP

      DOM 型 XSS 是因为前端 JS 直接使用用户输入操作 DOM,没有过滤,从而执行了恶意脚本。


      三、绕过技巧:

      HTML 实体编码

      HTML 实体编码(HTML Entity Encoding)是把具有特殊意义的字符,转换为浏览器不会解释的“安全格式”的一种方式。

      为何需要?

      浏览器会把 当作 HTML/JS 执行,造成 XSS 漏洞。但如果变成:

      <script>alert(1)</script>
      

      浏览器只会显示文本,而不会执行脚本。

      1. 常见 HTML 实体字符对照表

      原始字符 HTML 实体 描述
      < < 小于号(标签起始)
      > > 大于号(标签结束)
      & & 与号
      " " 双引号
      ' ' 单引号(也可 '
      / / 正斜杠(某些情况需要)

      2. 作用机制(原理)

      浏览器在渲染 HTML 时:

      • 识别实体字符(如 <

      • 显示为普通字符 <,但不作为 HTML 标签解析

      例如,下面代码:

      <script>alert(1)</script>

      显示结果是:

      
      

      但这段代码不会执行,因为不是 HTML 中的真正

    • 写到事件触发器中(如

    • 写到