一次对浏览器解析和XSS的深度探究
字数 1633 2025-08-18 11:39:15
浏览器解析与XSS防御深度解析
一、编码基础概念
为什么要进行编码
- 数据传输问题:Size过大、包含隐私数据、字符引起歧义
- URL编码原因:防止特殊字符(如
&)分割参数 - HTML编码原因:防止
<和>被识别为标签
二、三种主要编码方式
2.1 HTML编码(字符实体)
- 表示方法:
- 实体名称:
< - 实体编号:
<
- 实体名称:
- 常用字符实体:
字符 实体名称 实体编号 < <<> >>& &&" ""
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转义序列的三种位置
- 字符串中:作为普通字符处理
<script>alert("\u0031\u0030");</script> <!-- 输出"10" --> - 标识符中:会被解码为标识符
<script>\u0061\u006c\u0065\u0072\u0074(10);</script> <!-- 执行alert(10) --> - 控制字符中:解码后不再作为控制字符
<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="javascript:alert(2)"></a> <!-- 正常执行 -->
四、解析顺序与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编码
- 上下文感知:根据输出位置采用不同编码
示例对比
<!-- 不安全:仅HTML编码 -->
<!-- 弹窗两次 -->
<!-- 安全:先JS编码再HTML编码 -->
<!-- 不执行 -->
五、工具推荐
- CyberChef:多功能编解码工具,可用于分析复杂编码场景
六、总结要点
- 理解三种编码方式的区别和应用场景
- 掌握浏览器解析顺序:HTML→(URL/JS)→(URL/JS)
- 原始文本元素(
<script>,<style>)不解析HTML实体 - JavaScript中控制字符编码后将失效
- URL Scheme部分必须保持未编码状态
- 防御XSS应采用先JS编码再HTML编码的策略
通过深入理解浏览器解析机制和编码原理,可以有效预防XSS攻击,构建更安全的Web应用。