深入理解浏览器解析机制和XSS向量编码

news2025/7/19 21:03:01

目录

1、HTML解析

字符实体(character entities)

HTML字符实体(HTML character entities)

字符引用(character references)

在HTML中有五类元素

五类元素的区别如下

深入了解下RCDATA元素

2、URL解析

3、JavaScript解析

4、解析流


1、HTML解析

从XSS的角度来说,我们感兴趣的是HTML文档是如何被词法解析的,因为我们并不想让用户提供的数据最终被解析为一段可执行脚本的script标签。HTML词法解析细则在这里(http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html )。

一个HTML解析器作为一个状态机,它从输入流中获取字符并按照转换规则转换到另一种在状态。在解析过程中,任何时候它只要遇到一个'<'符号(后面没有跟'/'符号)就会进入"标签开始状态(Tag open state)"。然后转变到"标签名状态(Tag name state)","前属性名状态(before attribute name state)"......最后进入"数据状态(Data state)"并释放当前标签的token。当解析器处于"数据状态(Data state)" 时,它会继续解析,每当发现一个完整的标签,就会释放出一个token。

这里有三种情况可以容纳字符实体,"数据状态中的字符引用","RCDATA状态中的字符引用"和"属性值状态中的字符引用"。在这些状态中HTML字符实体将会从“&#...”形式解码,对应的解码字符会被放入数据缓冲区中。

例如

<div>&#60;img src=x onerror=alert(4)&#62;</div>

当“<”和“>”字符被编码为“&#60”和“&#62”。当解析器解析完“<div>”并处于“数据状态”时,这两个字符将会被解析。 当解析器遇到“&”字符,它会知道这是“数据状态的字符引用”,因此会消耗一个字符引用(例如“&#60”)并释放出对应字符的token。在这个例子中,对应字符指的是“<”和“>”。

此时解码后,脚本会执行吗?

答案是不会。原因是解析器在解析这个字符引用后不会转换到"标签开始状态"。因此,我们能够利用字符实体编码这个行为来转义用户输入的数据从而确保用户输入的数据只能被解析成“数据”。

通俗来讲就是解码后的"<"和">"不会被转换为"标签开始状态",因此就无法识别此标签,从而无法实现脚本的执行,也就无法实现弹窗。

字符实体(character entities)

字符实体是一个转义序列,它定义了一般无法在文本内容中输入的单个字符或符号。一个字符实体以&符号开始,后面跟着一个预定义的实体的名称,或是一个#符号以及字符的十进制数字。

HTML字符实体(HTML character entities)

在HTML中,某些字符是预留的。例如在HTML中不能使用"<"或">",这是因为浏览器可能误认为它们是标签的开始或结束。如果希望正确的显示预留字符,就需要在HTML中使用对应的字符实体。一个HTML字符实体描述如下:

字符引用(character references)

字符引用包括"字符值引用 "和"字符实体引用"。在上述HTML例子中,'<'对应的字符值引用为'&#60',对应的字符实体引用为'&lt'。字符实体引用也被叫做"实体引用"或"实体"。

在HTML中有五类元素

1、空元素(Void elements),如<area>,<br>,<base>等等

2、原始文本元素(Raw text elements),有<script>和<style>

3、RCDATA元素(RCDATA elements),有<textarea>和<title>

4、外部元素(Foreign elements),例如MathML命名空间或者SVG命名空间的元素

5、基本元素(Normal elements),即除了以上4种元素以外的元素

五类元素的区别如下

1、空元素 --- 不能容纳任何元素(因为它们没有闭合标签,没有内容能够放在开始标签和闭合标签中间)

2、原始文本元素 --- 可以容纳文本

2、RCDATA元素 --- 可以容纳文本和字符引用

4、外部元素 --- 可以容纳文本、字符引用、CDATA字段、其他元素和注释

5、基本元素 --- 可以容纳文本、字符引用、其他元素和注释

深入了解下RCDATA元素

例题1

<textarea>&#60;script&#62;alert(5)&#60;/script&#62;</textarea>

上述的脚本能执行吗?

答案是不能。原因是在HTML解析器的规则,其中有一种可以容纳字符引用的情况是“RCDATA状态中的字符引用”。这意味着在<textarea>和<title>标签中的字符引用会被HTML解析器解码。

但是,在解析这些字符引用的过程中不会进入"标签开始状态",因此无法执行,从而无法实现弹窗。

例题2

<textarea><script>alert(6)</script></textarea>

上述的脚本能执行吗?

答案是不能。原因是对RCDATA有个特殊的情况。在浏览器解析RCDATA元素的过程中,解析器会进入"RCDATA状态"。在这个状态中,如果遇到"<"字符,它会转换到"RCDATA小于号状态"。如果"<"字符后没有紧跟着"/"和对应的标签名,解析器会转换回“RCDATA状态”。这意味着在RCDATA元素标签的内容中(例如<textarea>或<title>的内容中),唯一能够被解析器认做是标签的就是“</textarea>”或者"</title>"。因此,在"<textarea>"和“<title>”的内容中不会创建标签,就不会有脚本能够执行。

通俗来讲就是,在RCDATA中的所有标签,HTML都不认识,它只认识自身的闭合标签(</textarea>和</title>),因此就无法执行脚本。

2、URL解析

URL解析器也是一个状态机模型,从输入流中进来的字符可以引导URL解析器转换到不同的状态。解析器的解析细则在这里(http://url.spec.whatwg.org/)。其中有很多有关安全或XSS转义的内容。

首先,URL资源类型必须是ASCII字母(U+0041-U+005A || U+0061-U+007A)。不然就会进入"无类型"状态。

例如

<a href="%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29"></a>

你不能对协议类型进行任何的编码操作,不然URL解析器会认为无类型。就如上述的情况一样。因为URL中被编码的"javascript"没有被解码,因此不会被URL解析器识别。该原则对协议后面的" : "(冒号)同样适用。

例如

<a href="&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;:%61%6c%65%72%74%28%32%29">

如果你记得我们在HTML解析部分讨论的内容的话,是否还记得有一个情况叫做“属性值中的字符引用”,在这个情况中字符引用会被解码。我们将稍后讨论解析顺序,但在这里,HTML解析器解析了文档,创建了标签token,并且对href属性里的字符实体进行了解码。然后,当HTML解析器工作完成后,URL解析器开始解析href属性值里的链接。在这时,"javascript"协议已经被解码,它能够被URL解析器正确识别。然后URL解析器继续解析链接剩下的部分。由于是"javascript"协议,JavaScript解析器开始工作并执行这段代码,最终代码能够被执行。

其次,URL编码过程使用UTF-8编码类型来编码每一个字符。如果你尝试着将URL链接做了其他编码类型的编码,URL解析器就可能不会正确识别。

3、JavaScript解析

JavaScript解析过程与HTML解析过程有点不一样。JavaScript语言是一门内容无关语言。对应着有一份内容无关的语法来描述它。我们可以利用内容无关语法来解释JavaScript是如何解析的。

ECMAScript-262细则在这里(http://www.ecma-international.org/publications/standards/Ecma-262.htm),语法文件在这里(http://www.antlr3.org/grammar/1206736738015/JavaScript.g )

这里有一些与安全相关的事情:字符是如何被解码的?对一些字符进行转义是否有效?

例如

<script>&#97;&#108;&#101;&#114;&#116&#40;&#57;&#41;&#59</script>

开始之前,让我们来回到HTML解析过程中的"原始文本"元素。所有的"script"块都属于"原始文本"元素。"script"块有个有趣的属性:在块中的字符引用并不会被解析和解码。如果你去看"脚本数据状态"的状态转换规则,就会发现没有任何规则能转移到字符引用状态。所以如果攻击者尝试着将输入数据编码成字符实体并将其放在script块中,它将不会被执行。

那像“\uXXXX”(例如\u0000,\u000A)这样的字符呢,JavaScript会解析这些字符来执行吗?简单的说:视情况而定。具体的说就是要看被编码的序列到底是哪部分。首先,像\uXXXX一样的字符被称作Unicode转义序列。从上下文来看,你可以将转义序列放在3个部分:字符串中,标识符名称中和控制字符中

字符串中:当Unicode转义序列存在于字符串中时,它只会被解释为正规字符,而不是单引号,双引号或者换行符这些能够打破字符串上下文的字符。这项内容清楚地写在ECMAScript中。因此,Unicode转义序列将永远不会破坏字符串上下文,因为它们只能被解释成字符串常量。

ECMAScript 与 JAVA 编程语言在对待Unicode转义序列时的行为不同。在Java程序中,如果Unicode转义序列\u000A出现在单行字符串注释中,它会被解释为行结束符(换行符),因此会导致接下来的Unicode字符不是注释的一部分。同样的,如果Unicode转义序列\u000A出现在Java程序的字符串常量中,它同样会被解释为行结束符(换行符),这在字符串常量中是不被允许的 --- 如果需要在字符串常量中表示换行,需要用\n来代替\u000A。在ECMAScript程序中,出现在注释中的Unicode转义序列永远不会被解释,因此不会导致注释换行问题。同样地,ECMAScript程序中,在字符串常量中出现的Unicode转义序列会被当作字符串常量中的一个Unicode字符,并且不会被解释成有可能结束字符串常量的换行符或者引号。

标识符名称中:当Unicode转义序列出现在标识符名称中时,它会被解码并解释为标识符名称的一部分,例如函数名,属性名等等。

例如

<script>\u0061\u006c\u0065\u0072\u0074(10);</script>

如果我们深入研究JavaScript细则,可以看到如下内容:

“Unicode转义序列(如\u000A\u000B)同样被允许用在标识符名称中,被当作名称中的一个字符。而将''符号前置在Unicode转义序列串(如\u000A000B000C)并不能作为标识符名称中的字符。将Unicode转义序列串放在标识符名称中是非法的。”

控制字符:当用Unicode转义序列来表示一个控制字符时,例如单引号、双引号、圆括号等等,它们将不会被解释成控制字符,而仅仅被解码并解析为标识符名称或者字符串常量。如果你去看ECMAScript的语法,就会发现没有一处会用Unicode转义序列来当作控制字符。

例如

如果解析器正在解析一个函数调用语句,圆括号部分必须为"("和")",而不能是\u0028和\u0029。

总的来说,Unicode转义序列只有在标识符名称里不被当作字符串,也只有在标识符名称里的编码字符能够被正常的解析。

例如

<script>\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0031\u0029</script>

不能执行的原因

因为“(11)”不会被正确的解析 ,而"alert(11)"也不是一个有效的标识符名称

例如

<script>\u0061\u006c\u0065\u0072\u0074(\u0031\u0032)</script>

不能执行的原因

因为'\u0031\u0032'不会被解释为字符串常量(因为它们没有用引号闭合)要么是因为它们是ASCII型数字。

例如

<script>alert('13\u0027)</script>

不能执行的原因

原因是'\u0027'仅仅会被解释成单引号文本,而此时字符串是未闭合的。

例如

<script>alert('14\u000a')</script>

不能执行的原因

原因是'\u000a'会被解释成换行符文本,这并不会导致真正的换行从而引发JavaScript语法错误。

4、解析流

在讨论过HTML,URL和JavaScript解析之后,读者应该能够对“什么会被解码”、“在什么地方被解码”和“如何被解码”这几件事有了清楚的认识。现在,另一个重要的概念是所有这些是如何协同工作的?在网页中有很多地方需要多个解析器来协同工作。因此,对于解码和转义问题,我们将简要的讨论浏览器如何解析一篇文档。

当浏览器从网络堆栈中获得一段内容后,触发HTML解析器来对这篇文档进行词法解析。在这一步中字符引用被解码。在词法解析完成后,DOM树就被创建好了,JavaScript解析器会介入来对内联脚本进行解析。在这一步中Unicode转义序列和Hex转义序列被解码。同时,如果浏览器遇到需要URL的上下文,URL解析器也会介入来解码URL内容。在这一步中URL解码操作被完成。由于URL位置不同,URL解析器可能会在JavaScript解析器之前或之后进行解析。考虑如下两种情况

Example A: <a href="UserInput"></a>
Example B: <a href=#   onclick="window.open('UserInput')"></a>

在例A中,HTML解析器将首先开始工作,并对UserInput中的字符引用进行解码。然后URL解析器开始对href值进行URL解码。最后,如果URL资源类型是JavaScript,那么JavaScript解析器会进行Unicode转义序列和Hex转义序列的解码。再之后,解码的脚本会被执行。因此,这里涉及三轮解码,顺序是HTML,URL和JavaScript

在例B中,HTML解析器首先工作。然而接下来,JavaScript解析器开始解析在onclick事件处理器中的值。这是因为在onclick事件处理器中是script的上下文。当这段JavaScript被解析并被执行的时候,它执行的是“window.open()”操作,其中的参数是URL的上下文。在此时,URL解析器开始对UserInput进行URL解码并把结果回传给JavaScript引擎。因此这里一共涉及三轮解码,顺序是HTML,JavaScript和URL。

有没有可能解码次数超过3轮呢?考虑一下这个例子

Example   C: <a href="javascript:window.open('UserInput')">

例C与例A很像,但不同的是在UserInput前多了window.open()操作。因此,对UserInput多了一次额外的URL解码操作。总的来说,四轮解码操作被完成,顺序是HTML,URL,JavaScript和URL。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/395483.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

es倒排索引原理

1、简介 网上看到的一篇文章&#xff0c;对Lucene的倒排索引是如何执行的&#xff0c;说的比较易懂&#xff0c;就转过来分享下。 Elasticsearch是通过Lucene的倒排索引技术实现比关系型数据库更快的过滤。特别是它对多条件的过滤支持非常好&#xff0c;比如年龄在18和30之间&a…

kubeadm安装K8S(集群)

前言市面上很多k8s的安装工具&#xff0c;作为产品的设计者和推广者&#xff0c;K8S组织也知道自己的产品部署起来十分的困难&#xff0c;于是把开源爱好者写的工具kubeadmn收编为正规军&#xff0c;纳入到了自己的麾下。为什么我们要用kubeadmn来部署&#xff1f;因为kubeadm不…

【代码实践】DeepBDC for few-shot learning代码运行

DeepBDC是Jiangtao Xie等人在CVPR2022上提出的few-shot classification方法&#xff0c;论文全名为“Joint Distribution Matters: Deep Brownian Distance Covariance for Few-Shot Classification”。本文旨在记录在Window系统下运行该官方代码&#xff08;https://github.co…

Linux学习第二十四节-Podman容器

一、容器的概念 容器是由一个或多个与系统其余部分隔离的进程组成的集合。我们可以理解为“集装箱”。 集装箱是打包和装运货物的标准方式。它作为一个箱子进行标记、装载、卸载&#xff0c;以及从一个 位置运输到另一个位置。该容器的内容与其他容器的内容隔离&#xff0c…

传统企业数字化转型真的有必要吗?应该如何做转型?

随着数字经济的快速发展&#xff0c;各行各业数字化转型成为必然。从最初的信息化建设&#xff0c;到数字企业、数字政府建设&#xff0c;再到如今的数字经济建设&#xff0c;传统企业在数字化转型中的作用越来越大。与此同时&#xff0c;数字化转型对传统企业提出了更高的要求…

【Java开发面试】AHXX面试总结

1. java中常用的集合有哪些 java中常用的集合类有List,Set,Map,其中List和Set继承了Collection。 List的实现类有&#xff1a;ArrayList&#xff0c;LinkedList&#xff0c;Vector&#xff0c;Stack Set的实现类有&#xff1a;TreeSet&#xff0c;HashSet Map的实现类有&#…

MySQL运维篇之读写分离

04、读写分离 4.1、介绍 读写分离&#xff0c;简单地说是把对数据库的读和写操作分开&#xff0c;以对应不同的数据库服务器。主数据库提供写操作&#xff0c;从数据库提供读操作&#xff0c;这样能有效地减轻单台数据库的压力。 通过Mycat即可轻易实现上述功能&#xff0c;…

02_Linux终端操作,shell命令,软件安装,文件系统结构,磁盘管理

目录 终端操作 常用Shell命令 Ubuntu软件安装方法 Ubuntu文件系统结构 绝对路径和相对路径 Ubuntn下磁盘管理 终端操作 打开终端快捷键Ctrlaltt 或鼠标右键 常用Shell命令 1.目录信息查看命令ls ls -a 显示目录所有文件及文件夹,包括隐藏文件,比如以.开头的 ls -l…

Synopsys Sentaurus TCAD系列教程之--Sprocess(SmallMOS_2D3D) 解析

SmallMOS_2D3D解析 #header## STI depth set sti_depth 0.15 ## Half STI width set sti_width sti_width ## Half gate length set gate_len <lg/2> ## SD length (from center) set sd_len [expr $gate_len0.05]#endheader## X lines line x location 0.0 spacing 0.…

OSI ARP TCP-IP HDCP

OSI七层参考模型分层名称基本功能应用层用户与网络、应用程序与网络的接口&#xff0c;直接向用户提供服务表示层处理用户信息的表示问题&#xff0c;如编码、数据格式转换和加密解密会话层组织和协调两个会话进程之间的通信传输层应用进程之间的连接&#xff0c;提供端到端的服…

Coremail邮件系统全新上线存档邮箱功能

邮箱积累邮件太多&#xff0c;搜索起来又慢又麻烦&#xff01; 我的重要邮件忘记下载丢失了&#xff01;14天自动删除太难了&#xff01; 有没有可能重要邮件自动存档&#xff0c;解救一下“遗忘星”人&#xff1f; 在我们日常工作中&#xff0c;邮件是最经常使用的办公工具之一…

Spark/Hive

Spark/HiveHive 原理Spark with HiveSparkSession Hive Metastorespark-sql CLI Hive MetastoreBeeline Spark Thrift ServerHive on SparkHive 擅长元数据管理Spark 擅长高效的分布式计算 Spark Hive 集成 : Hive on Spark : Hive 用 Spark 作为底层的计算引擎时Spark w…

【BOOST C++】组件编程(1)--动态链接库

一、说明 所谓组件工程&#xff0c;是指将某些功能函数&#xff08;类&#xff09;做成动态链接库的部分&#xff0c;在运行时调入。在调用功能类时&#xff0c;会调入、释放过程。因此&#xff0c;这里首先知道如何用动态链接库调入功能&#xff0c;然后知道如何才是组件。两个…

数字帆船VR虚拟体验教学有什么特色?

数字帆船VR虚拟体验教学是由广州华锐互动开发的一种应用VR虚拟现实技术的教学模式&#xff0c;通过VR技术&#xff0c;学生可以在虚拟的环境中模拟数字帆船的各个方面&#xff0c;包括横风航行、迎风航行、顺风航行等&#xff0c;在沉浸式的场景中获得更加真实的体验&#xff0…

ASEMI高压MOS管10N60参数,10N60特征,10N60大小

编辑-Z ASEMI高压MOS管10N60参数&#xff1a; 型号&#xff1a;10N60 漏极-源极电压&#xff08;VDS&#xff09;&#xff1a;600V 栅源电压&#xff08;VGS&#xff09;&#xff1a;30V 漏极电流&#xff08;ID&#xff09;&#xff1a;10A 功耗&#xff08;PD&#xff…

【Azure 架构师学习笔记】-Azure Storage Account(2)- Queue Storage

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Storage Account】系列。 接上文 【Azure 架构师学习笔记】-Azure Storage Account&#xff08;1&#xff09;-类型简介 前言 Azure Storage Queues 是一个专门用来处理基于云环境队列的Azure 服务。每个队列都维护着…

【(1+1+2+1+2+3+到1+2+3+到+n)】2023-3-5

缘由https://ask.csdn.net/questions/7895988鉴于初学知识储备不足认识模糊&#xff0c;这篇文章就从最基础的C知识入手&#xff0c;用详细资料来描述这个程序关联的知识&#xff0c;由于本程序使用一行语句完成运算&#xff0c;因此&#xff0c;将按运算符&#xff08;自左向右…

每天学一点之网络编程

网络编程 一、软件结构 C/S结构 &#xff1a;全称为Client/Server结构&#xff0c;是指客户端和服务器结构。常见程序有&#xff31;&#xff31;、迅雷&#xff0c;百度网盘。 B/S结构 &#xff1a;全称为Browser/Server结构&#xff0c;是指浏览器和服务器结构。常见浏览器…

go语言踩坑大全

文章目录1.左大括号 { 不能单独放一行2.未使用的变量3.未使用的 import4.简短声明的变量只能在函数内部使用5.使用简短声明来重复声明变量6.不能使用简短声明来设置字段的值7.覆盖了变量差错8.显式类型的变量无法使用 nil 来初始化9.直接使用值为 nil 的 slice、map10.map 容量…

CFS三层靶机安装与配置

CFS三层靶机安装与配置 环境下载 百度网盘 提取码&#xff1a;Chen 环境安装 下载完成后&#xff0c;有三个文件夹&#xff0c;每个文件夹对应一个靶机 进入三个文件夹&#xff0c;双击打开后缀为.ovf的文件&#xff0c;按提示安装虚拟机 环境配置 网段划分 target1&#…