XSS与字符编码基本介绍:
提起XSS 想到的就是插入字符字符编码与各种解析了!现在介绍一下在xss中最经常用到的编码
html实体编码(10进制与16进制):
如把尖括号编码[ < ] -----> html十进制: < html十六进制: c;
javascript的八进制跟十六进制:
如把尖括号编码[ < ] -----> js八进制: \74 js十六进制: \x3c
jsunicode编码:
如把尖括号编码[ < ] ----->jsunicode: \u003c
url编码 base64编码:
如把尖括号编码[ < ] -----> url: %3C base64: PA==
html实体编码
html实体编码本身存在的意义是防止与HTML本身语义标记的冲突。但是在XSS中却成为了的一大利器,但是也不能盲目的使用!
html中正常情况只识别:html10进制,html16进制
应该如何在xss过程中灵活的使用各种编码呢?
比如现在你的输出点在这:
<img src="[代码]">
在这里过滤了script < > / \ http: 以及各种危险字符 比如创建一个html节点什么的!
有的站只允许你引用一个img文件夹里的图片 但是图片是你可以控的 可以通过抓包来修改的!
我们如果想加载外部js 或者一个xss平台的钩子我们应该怎么写呢?
那么我们可以在这里 闭合双引号 写事件: onerror=[html language="实体编码"][/html][/html]
比如现在弹个窗:
<img src="x" onerror="	 7;
 8;
 1; 4; 6; 0; 9; 1;">
这里在编码中加了空格因为编码会被解析为下面的:
原code:
<img src="x" onerror="alert(1)">
这里用的是html十进制编码 也可以使用十六进制的html实体编码
浏览器解析原理(参照https://blog.csdn.net/u010726042/article/details/76259398)
解析过程:
浏览器在解析HTML文档时无论按照什么顺序,主要有三个过程:HTML解析、JS解析和URL解析,每个解析器负责HTML文档中各自对应部分的解析工作。下面以一篇HTML文档解析来简单的讨论下解析器如何协同工作的。
首先浏览器接收到一个HTML文档时,会触发HTML解析器对HTML文档进行词法解析(解析器-词法分析器 Parser-Lexer combination
解析可以分为两个子过程——语法分析及词法分析词法分析就是将输入分解为符号,符号是语言的词汇表——基本有效单元的集合。对于人类语言来说,它相当于我们字典中出现的所有单词。语法分析指对语言应用语法规则。解析器一般将工作分配给两个组件——词法分析器(有时也叫分词器)负责将输入分解为合法的符号,解析器则根据语言的语法规则分析文档结构,从而构建解析树,词法分析器知道怎么跳过空白和换行之类的无关字符。),
这一过程完成HTML解码并创建DOM树,接下来JavaScript解析器会介入对内联脚本进行解析,这一过程完成JS的解码工作,如果浏览器遇到需要URL的上下文环境,这时URL解析器也会介入完成URL的解码工作,URL解析器的解码顺序会根据URL所在位置不同,可能在JavaScript解析器之前或之后解析。每个解析过程中也有许多细节,下面再做具体讨论。
基本概念:
HTML字符实体:
在呈现HTML页面时,针对某些特殊字符如“<”或”>”直接使用,浏览器会误以为它们标签的开始或结束,若想正确的在HTML页面呈现特殊字符就需要用到其对应的字符实体。
字符实体是一个预先定义好的转义序列,它定义了一些无法在文本内容中输入的字符或符号。字符实体以&开头+预先定义的实体名称,以分号结束,如“<”的实体名称为< 或以&开头+#符号以及字符的十进制数字,如”<”的实体编号为<,字符都是有实体编号的但有些字符没有实体名称。
JavaScript编码:最常用的如“\uXXXX”这种写法为Unicode转义序列,表示一个字符,其中xxxx表示一个16进制数字,如”<” Unicode编码为“\u003c”。
URL编码:%加字符的ASCII编码对于的2位16进制数字,如”/”对应的URL编码为%2f。
下面结合具体示例来讨论下浏览器的解析原理过程和XSS复合编码的一些内容:
<a href="javascript:alert(1)">test</a>
针对上述a标签我们分析一下该环境中浏览器的解析顺序,首先HTML解析器开始工作,并对href中的字符做HTML解码,接下来URL解析器对href值进行解码,正常情况下URL值为一个正常的URL链接,如:“https://www.yirendai.com“,那么URL解析器工作完成后是不需要其他解码的,但是该环境中URL资源类型为JavaScript,因此该环境中最后一步JavaScript解析器还会进行解码操作,最后解析的脚本被执行。
整个解析顺序为3个环节:HTML解码àURL解码àJS解码
我们对href值做一些编码的转换,对照刚才分析的解析过程,思考一下脚本是否会正常执行?
Test1:URL 编码 "javascript:alert(1)”
URL编码“javascript:alert(1)”=“%6A%61%76%61%73%63%72%69%70%74:%61%6C%65%72%74%28%31%29”
编码后:
<a href="%6A%61%76%61%73%63%72%69%70%74:%61%6C%65%72%74%28%31%29">test1</a>
test2:HTML字符实体编码 "javascript" 、URL 编码 "alert(2)"
HTML编码"javascript"="javascript"
URL编码"alert(2)"=” %61%6C%65%72%74%28%32%29”
<a href="javascript:%61%6C%65%72%74%28%32%29">test2</a>
Test3:对<a href="javascript:alert(3)">test3</a>做JS编码àURL编码àHTML编码共3层。
JS编码:<a href="javascript:\u0061\u006c\u0065\u0072\u0074(3)">test3</a>
URL编码:<a href="javascript:%5c%75%30%30%36%31%5c%75%30%30%36%63%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34(3)">test3</a>
HTML编码:<a href="javascript:%5c%75%30%30%36%31%5c%75%30%30%36%63%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34(3)">test3</a>
经测试只有2和3可以弹窗,1不能。
【过程分析】
许多童鞋把Test1放到HTML里发现脚本并没有正常执行,就会想按照刚才分析的,URL解码之后Javascript解析器完成解码操作,脚本应该会正常执行啊,这里就有一个URL解析过程中的一个细节了,不能对协议类型进行任何的编码操作,否则URL解析器会认为它无类型,就导致Test1中被编码的“javascript”没有解码,当然不会被URL解析器识别了。
那Test2也是对javascript编码了为什么可以执行呢?因为"javascript"是做的HTML实体编码,HTML解析器工作时,href里的HTML实体会被解码,接下来URL解析器工作解析href属性里的链接时,"javascript"协议在第一步被HTML解码了,这样URL解析器是可以识别的,然后继续解析后面的”%61%6C%65%72%74%28%32%29”,最后JavaScript解析器完成解析操作,脚本执行。
Test3实现了3层复合编码,每一层编码都能正常执行,贴出来供大家可以自行验证加深理解
<img src=x onclick=” {$value}”>
下面我们分析一下2层复合编码的img标签
代码如下:
假设onclick属性值为“用户可控”数据,思考一下该如何编码才能防住XSS?
首先传入的“用户可控”数据处在HTML环境中,然后再是onclick环境中,因此浏览器的解析顺序为:HTML解码àJS解码;
HTML解码: \u0061\u006c\u0065\u0072\u0074('YISRC')
JS解码:alert('YISRC')
解码完成,脚本执行,细心的童鞋可能会问了value值的编码顺序为解码的逆序,先将alert进行javascript编码为\u0061\u006c\u0065\u0072\u0074,然后再对整个value值进行HTML编码,居然还可以弹框?
我们来分析一下JavaScript解析的一个细节,Javascript解析器工作的时候将\u0061\u006c\u0065\u0072\u0074进行js解码后为“alert”,而“alert”是一个有效的标识符名称,它是能被正常解析的。像圆括号、双引号、单引号等等这些控制字符,在进行JavaScript解析的时候仅会被解码为字符串文本或者上面讲的标识符名称,例如:<script>alert('YISRC\u0027)</script>对控制字符单引号进行js编码,解析时\u0027被解码成文本单引号,无法闭合因此不能成功执行。本例中只对“alert”进行了Unicode,并没有对圆括号这类控制字符进行Unicode,是因为我想弹框啊,但在正常的XSS防御中肯定要对这些控制字符进行Unicode的。
下面通过几个简单的场景加深理解一下:
假设:alert里的值为用户输入的可控数据,服务端为了防御XSS做了HTML编码
示例一:
用户输入的【");alert("SRC】在服务端HTML实体编码之后返回到前端被浏览器解析执行
1、首先【");alert("SRC 】在HTML解码后变成了【");alert("SRC】。
2、JavaScript解析时,变成了【alert("YISRC ");alert("SRC】,当然可以正常执行了,如下图所示:
事实证明,该上下文环境中只做HTML编码是不能完全防御XSS的。
示例二:
现在调整服务端XSS防御策略为:JS编码àHTML编码
如下图所示,成功防御:
来分析一下:
1、首先【\u0027\u0029\u003b\u0061\u006c\u0065\u0072\u0074\u0028\u0027\u0053\u0052\u0043】经过第一步HTML解码后变为【\u0027\u0029\u003b\u0061\u006c\u0065\u0072\u0074\u0028\u0027\u0053\u0052\u0043】
2、JavaScript解析器工作,【\u0027\u0029\u003b\u0061\u006c\u0065\u0072\u0074\u0028\u0027\u0053\u0052\u0043】变为【');alert('SRC】,刚才已经讲过JavaScript解析时只有标识符名称不会被当做字符串,控制字符仅会被解析为标示符名称或者字符串,因此'\u0027'被解释成单引号文本,\u0028和\u0029被解释成为圆括号文本,不会变为控制字符被解析执行。
事实证明,合理的编码方式是防御XSS中首先要考虑到的。
结合上面的内容,自己分析一下value1和value2所处的上下文环境,要防御XSS需要怎么做组合编码?
浏览器解码顺序:
Value1:HTML解码àJavaScript解码àURL解码
Value2:HTML解码àURL解码àJavaScript解码àURL解码