当前位置: 首页 > java >正文

【前端安全】聊聊 HTML 闭合优先级和浏览器解析顺序

【前端安全】聊聊浏览器解析顺序和 HTML 闭合优先级

最近在研究 XSS 的时候,发现一个特别容易被忽略的问题 —— 浏览器到底是怎么解析 HTML 的?为什么有些 payload 成功了,有些却怎么试都不行?其实这跟标签的闭合优先级还有解析顺序有很大关系。

这篇文章就来聊聊这个问题,顺便整理一下我踩过的坑和总结的规律。


一、浏览器是怎么解析 HTML 的?

我们都知道浏览器是按顺序从上往下解析 HTML 的,但有一点容易忽略:

只要遇到 <script>,浏览器就会暂停 DOM 的解析,优先执行里面的 JS。

也就是说,DOM 结构和 JS 是交替解析的,而不是一起解析的。

举个栗子:

<p>前面的标签</p>
<script>alert('中间插入了一段 JS');
</script>
<p>后面的标签</p>

alert() 执行完之前,后面的 <p> 标签都不会被解析进 DOM 树里。


二、HTML 和 JS 中的“编码解析”

HTML 中能解析的编码

HTML 中的属性值,比如 <img>srconerror,是可以解析一些编码的:

比如:

<img src=x onerror=&#97;lert(1)>

&#97; 实际上是字符 a,所以这里最终会执行 alert(1)

更复杂一点的:

<img src="1"onerror=&#92;&#117;&#48;&#48;&#54;&#49;&#92;&#117;&#48;&#48;&#54;&#99;&#92;&#117;&#48;&#48;&#54;&#53;&#92;&#117;&#48;&#48;&#55;&#50;&#92;&#117;&#48;&#48;&#55;&#52;&#40;&#39;&#92;&#117;&#48;&#48;&#51;&#49;&#39;&#41;>

这是一堆 Unicode 转义,浏览器会还原成 JS 代码。虽然看着很花,但其实本质还是在执行 alert('1')

JS 里的编码也能玩花样

<script>
\u0061lert("<HelloWorld>");
</script>

\u0061a,所以这行代码其实就是 alert("<HelloWorld>")

这些“编码绕过”技巧在 XSS 中经常用到,尤其是某些过滤器只过滤了关键词,但没处理 Unicode 或 HTML 实体的时候,简直不要太好用。


三、结构性字符不可用编码绕过

有些结构性字符,是不能轻易编码的,否则浏览器会把它当成“普通值”,根本不当回事。

字符作用
"属性值起始/结束
'属性值起始/结束
=属性赋值符号
<标签起始
>标签结束
/结束标签的斜杠
空格属性之间的分隔

比如下面这个例子就失败了

<img src="&quot; onerror&equals;alert(1) &quot;">

你以为你写了 onerror=alert(1),但浏览器根本不认,它只会当成一个超长的 src 值。


四、比双引号闭合优先级更高的标签

有一类标签,你一旦打开,里面写啥都不会被解析成 HTML 标签或属性,直到你显式地把它关闭。

这些标签包括:

<!--
<iframe>
<noframes>
<noscript>
<script>
<style>
<textarea>
<title>
<xmp>

举个真实的 payload:

<script>var a="</script><script>alert(1);var a=""</script>

在第一个 <script> 中的字符串没闭合,导致后面的 </script> 被当成字符串的一部分吃掉了,浏览器继续往下读,直到遇到下一个 <script> 标签,再继续执行。于是 alert(1) 就偷偷溜进去了。

这种技巧经常被用来构造逃逸型 XSS,非常常见。

在这里插入图片描述
附一个好用的短xss payload网站
https://tinyxss.terjanq.me/

http://www.xdnf.cn/news/16987.html

相关文章:

  • 《嵌入式数据结构笔记(一):数据结构导论与链表》
  • Libevent(5)之使用教程(4)工具
  • 对接古老系统的架构实践:封装混乱,走向有序
  • 《从原理到实践:MySQL索引优化与SQL性能调优全解析》
  • Axios介绍
  • 达梦数据库备份与还原终极指南:从基础到增量策略实战
  • k8s+isulad 国产化技术栈云原生技术栈搭建4-添加worker节点
  • 使用Database Navigator插件进行连接sqlite报错invalid or incomplete database
  • 新电脑上GitHub推送失败?全面排查与解决指南
  • 力扣经典算法篇-41-旋转图像(辅助数组法,原地旋转法)
  • 基于深度学习的医学图像分析:使用变分自编码器(VAE)实现医学图像生成
  • 华为智能家居与Spring人工智能
  • PyTorch生成式人工智能(24)——使用PyTorch构建Transformer模型
  • 06.Redis 配置文件说明
  • C++ <type_traits> 应用详解
  • 需求和测试的映射关系
  • 推荐一款进程间高速交换数据的解决方案
  • 前端JS-调用单删接口来删除多个选中文件
  • 操作系统——读者写者问题
  • Spring **${}** vs **#{}** 语法全景图
  • 【C++ 初级工程师面试--5】inline内联函数特点 、和普通函数的区别、什么时候适合内联?
  • Shell脚本-变量如何定义
  • 什么是DOM和BOM?
  • 搜索引擎评估革命:用户行为模型如何颠覆传统指标?
  • 数据结构1-概要、单向链表
  • [网安工具] Web 漏洞扫描工具 —— AWVS · 使用手册
  • 【C语言】内存函数与数据在内存中的存储
  • python -m build打包成为tar.gz或者whl
  • Qemu-NUC980(二):时钟clock代码添加
  • Redis数据库存储键值对的底层原理