一次对浏览器解析和XSS的深度探究
字数 1633 2025-08-18 11:39:15

浏览器解析与XSS防御深度解析

一、编码基础概念

为什么要进行编码

  • 数据传输问题:Size过大、包含隐私数据、字符引起歧义
  • URL编码原因:防止特殊字符(如&)分割参数
  • HTML编码原因:防止<>被识别为标签

二、三种主要编码方式

2.1 HTML编码(字符实体)

  • 表示方法
    • 实体名称:&lt;
    • 实体编号:&#60;
  • 常用字符实体
    字符 实体名称 实体编号
    < &lt; &#60;
    > &gt; &#62;
    & &amp; &#38;
    " &quot; &#34;

2.2 JavaScript编码

  • Unicode转义序列:\uXXXX(如<编码为\u003c
  • 使用场景:字符串、标识符、控制字符

2.3 URL编码

  • 格式:%+ASCII十六进制值(如/编码为%2f
  • JavaScript编码函数:
    • escape()
    • encodeURI()
    • encodeURIComponent()

三、浏览器解析规则

3.1 HTML解析器

HTML元素分类

  1. 空元素:``, <br>(无闭合标签)
  2. 原始文本元素<script>, <style>
  3. RCDATA元素<textarea>, <title>
  4. 外部元素:MathML/SVG命名空间
  5. 基本元素:其他所有元素

解析状态

  • 数据状态(Data State):解码字符实体
  • 标签打开状态(Tag Open State):识别标签开始
  • RCDATA状态:解码字符实体但不解析标签

关键特性

  • 原始文本元素(<script>, <style>)中的字符实体不会被HTML解码
  • RCDATA元素中的字符实体会被解码,但不会解析为HTML标签

3.2 JavaScript解析器

Unicode转义序列的三种位置

  1. 字符串中:作为普通字符处理
    <script>alert("\u0031\u0030");</script> <!-- 输出"10" -->
    
  2. 标识符中:会被解码为标识符
    <script>\u0061\u006c\u0065\u0072\u0074(10);</script> <!-- 执行alert(10) -->
    
  3. 控制字符中:解码后不再作为控制字符
    <script>alert\u0028"xss");</script> <!-- 不执行 -->
    

重要规则

  • 控制字符((), '', "")编码后将失去控制功能
  • 标识符名称中的编码会被正常解码

3.3 URL解析器

关键规则

  • Scheme部分(如javascript:不能被编码
  • :字符不能被编码
  • 解析顺序影响最终结果

示例分析

<a href="javascript:alert(1)"></a> <!-- 正常执行 -->
<a href="%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29"></a> <!-- 不执行 -->
<a href="&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;:alert(2)"></a> <!-- 正常执行 -->

四、解析顺序与XSS防御

4.1 解析顺序规则

  1. HTML解析器首先工作(总是第一步)
  2. URL解析器JavaScript解析器顺序取决于上下文:
    • <a href="UserInput">:HTML→URL→JS
    • <a onclick="window.open('UserInput')">:HTML→JS→URL
    • <a href="javascript:window.open('UserInput')">:HTML→URL→JS→URL

4.2 XSS防御最佳实践

防御策略

  1. 输入过滤:对用户输入进行严格验证
  2. 输出编码
    • 先进行JavaScript编码
    • 再进行HTML编码
  3. 上下文感知:根据输出位置采用不同编码

示例对比

<!-- 不安全:仅HTML编码 -->
 <!-- 弹窗两次 -->

<!-- 安全:先JS编码再HTML编码 -->
 <!-- 不执行 -->

五、工具推荐

  • CyberChef:多功能编解码工具,可用于分析复杂编码场景

六、总结要点

  1. 理解三种编码方式的区别和应用场景
  2. 掌握浏览器解析顺序:HTML→(URL/JS)→(URL/JS)
  3. 原始文本元素(<script>, <style>)不解析HTML实体
  4. JavaScript中控制字符编码后将失效
  5. URL Scheme部分必须保持未编码状态
  6. 防御XSS应采用先JS编码再HTML编码的策略

通过深入理解浏览器解析机制和编码原理,可以有效预防XSS攻击,构建更安全的Web应用。

浏览器解析与XSS防御深度解析 一、编码基础概念 为什么要进行编码 数据传输问题 :Size过大、包含隐私数据、字符引起歧义 URL编码原因 :防止特殊字符(如 & )分割参数 HTML编码原因 :防止 < 和 > 被识别为标签 二、三种主要编码方式 2.1 HTML编码(字符实体) 表示方法 : 实体名称: &lt; 实体编号: &#60; 常用字符实体 : | 字符 | 实体名称 | 实体编号 | |------|----------|----------| | < | &lt; | &#60; | | > | &gt; | &#62; | | & | &amp; | &#38; | | " | &quot; | &#34; | 2.2 JavaScript编码 Unicode转义序列: \uXXXX (如 < 编码为 \u003c ) 使用场景:字符串、标识符、控制字符 2.3 URL编码 格式: % +ASCII十六进制值(如 / 编码为 %2f ) JavaScript编码函数: escape() encodeURI() encodeURIComponent() 三、浏览器解析规则 3.1 HTML解析器 HTML元素分类 空元素 : ``, <br> (无闭合标签) 原始文本元素 : <script> , <style> RCDATA元素 : <textarea> , <title> 外部元素 :MathML/SVG命名空间 基本元素 :其他所有元素 解析状态 数据状态(Data State) :解码字符实体 标签打开状态(Tag Open State) :识别标签开始 RCDATA状态 :解码字符实体但不解析标签 关键特性 原始文本元素( <script> , <style> )中的字符实体 不会 被HTML解码 RCDATA元素中的字符实体会被解码,但不会解析为HTML标签 3.2 JavaScript解析器 Unicode转义序列的三种位置 字符串中 :作为普通字符处理 标识符中 :会被解码为标识符 控制字符中 :解码后不再作为控制字符 重要规则 控制字符( () , '' , "" )编码后将失去控制功能 标识符名称中的编码会被正常解码 3.3 URL解析器 关键规则 Scheme部分(如 javascript: ) 不能 被编码 : 字符 不能 被编码 解析顺序影响最终结果 示例分析 四、解析顺序与XSS防御 4.1 解析顺序规则 HTML解析器 首先工作(总是第一步) URL解析器 和 JavaScript解析器 顺序取决于上下文: <a href="UserInput"> :HTML→URL→JS <a onclick="window.open('UserInput')"> :HTML→JS→URL <a href="javascript:window.open('UserInput')"> :HTML→URL→JS→URL 4.2 XSS防御最佳实践 防御策略 输入过滤 :对用户输入进行严格验证 输出编码 : 先进行JavaScript编码 再进行HTML编码 上下文感知 :根据输出位置采用不同编码 示例对比 五、工具推荐 CyberChef :多功能编解码工具,可用于分析复杂编码场景 六、总结要点 理解三种编码方式的区别和应用场景 掌握浏览器解析顺序:HTML→(URL/JS)→(URL/JS) 原始文本元素( <script> , <style> )不解析HTML实体 JavaScript中控制字符编码后将失效 URL Scheme部分必须保持未编码状态 防御XSS应采用先JS编码再HTML编码的策略 通过深入理解浏览器解析机制和编码原理,可以有效预防XSS攻击,构建更安全的Web应用。