此测试为HTML的js协议编码弹窗测试,用于今后的反射型xss弹窗测试
在基本元素下将语句全部进行url编码
<a href="%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29">aaaa</a>
<a href="javascript:alert(1)">aaaa</a> #注:想要生成的弹窗语句,下同
执行结果:

显示为访问拒绝,可以看到通过url编码的函数,无法通过html直接转码成可执行的函数。
原因:
里面没有HTML编码内容,不考虑,其中href内部是URL,于是直接丢给URL模块处理,但是协议无法识别(即被编码的javascript:),解码失败,不会被执行
url在处理时会优先识别协议,但此时的js函数被url编码过了故url模块无法识别,无法进行弹窗。
在基本元素下将语句进行html实体编码及url编码
<a href="javascript:%61%6c%65%72%74%28%32%29">aaaa</a>
<a href="javascript:alert(2)">aaaa</a>
执行结果:

原因:
由于这里的语句写在html中所以会先执行html解码,又href中存在html实体编码,所以会先进行html解码成为js函数,再交给href中的url模块进行处理。后面的url编码内容会直接进行url解码,于是被执行。
具体过程:
1.先HTML解码,得到
<a href="javascript:%61%6c%65%72%74%28%32%29">
2.href中为URL,URL模块可识别为javascript协议,进行URL解码,得到
<a href="javascript:alert(2)">
由于是javascript协议,解码完给JS模块处理,于是被执行
在基本元素下将语句中的冒号进行url编码
<a href="javascript%3aalert(3)">aaaa</a>
<a href="javascript:alert(3)">aaaa</a>
执行结果:

原因:与1.的原因相同,故不赘述
在基本元素下将语句的间括号进行html实体编码
<div><img src=x onerror=alert(4)></div>
<div><img src=x onerror=alert(4)></div>
执行结果:

未生成弹窗
原因:
从HTML解析机制看,在读取<div>之后进入数据状态,<会被HTML解码,但不会进入标签开始状态,同时就不会建立新标签,当然也就不会创建img元素,也就不会执行
一个HTML解析器作为一个状态机,它从输入流中获取字符并按照转换规则转换到另一种状态。在解析过程中,任何时候它只要遇到一个'<'符号(后面没有跟'/'符号)就会进入“标签开始状态(Tag open state)”。然后转变到“标签名状态(Tag name state)”,“前属性名状态(before attribute name state)”......最后进入“数据状态(Data state)”并释放当前标签的token。当解析器处于“数据状态(Data state)”时,它会继续解析,每当发现一个完整的标签,就会释放出一个token。
这里有三种情况可以容纳字符实体,“数据状态中的字符引用”,“RCDATA状态中的字符引用”和“属性值状态中的字符引用”。在这些状态中HTML字符实体将会从“&#...”形式解码,对应的解码字符会被放入数据缓冲区中。例如,在问题4中,“<”和“>”字符被编码为“<”和“>”。当解析器解析完“<div>”并处于“数据状态”时,这两个字符将会被解析。当解析器遇到“&”字符,它会知道这是“数据状态的字符引用”,因此会消耗一个字符引用(例如“<”)并释放出对应字符的token。在这个例子中,对应字符指的是“<”和“>”。读者可能会想:这是不是意味着“<”和“>”的token将会被理解为标签的开始和结束,然后其中的脚本会被执行?答案是脚本并不会被执行。原因是解析器在解析这个字符引用后不会转换到“标签开始状态”。正因为如此,就不会建立新标签。因此,我们能够利用字符实体编码这个行为来转义用户输入的数据从而确保用户输入的数据只能被解析成“数据”。
理解:将<>转译为html的实体编码“<”和“>”确实会被html解码,不过html为保证信息安全,脚本并不会被执行。原因是解析器在解析这个字符引用后不会转换到“标签开始状态”。正因为如此,就不会建立新标签。导致脚本执行失败
RCDATA元素下将语句的间括号进行html实体编码
这里我们使用的是RCDATA元素<textarea>
这里要提一下RCDATA的概念。要了解什么是RCDATA,我们先要了解另一个概念。在HTML中有五类元素:
空元素(Void elements),如<area>,,<base>等等
原始文本元素(Raw text elements),有<script>和<style>
RCDATA元素(RCDATA elements),有<textarea>和<title>
4.外部元素(Foreign elements),例如MathML命名空间或者SVG命名空间的元素
5.基本元素(Normal elements),即除了以上4种元素以外的元素
五类元素的容纳区别如下:
空元素,不能容纳任何内容(因为它们没有闭合标签,没有内容能够放在开始标签和闭合标签中间)。
原始文本元素,可以容纳文本。
RCDATA元素,可以容纳文本和字符引用。
外部元素,可以容纳文本、字符引用、CDATA段、其他元素和注释
基本元素,可以容纳文本、字符引用、其他元素和注释
<textarea><script>alert(5)</script></textarea>
<textarea><script>alert(5)</script></textarea>
执行结果:

未生成弹窗
原因:
有一种可以容纳字符引用的情况是“RCDATA状态中的字符引用”。这意味着在<textarea>和<title>标签中的字符引用会被HTML解析器解码。这里要再提醒一次,在解析这些字符引用的过程中不会进入“标签开始状态”。故没有生成弹窗
另外,对RCDATA有个特殊的情况。在浏览器解析RCDATA元素的过程中,解析器会进入“RCDATA状态”。在这个状态中,如果遇到“<”字符,它会转换到“RCDATA小于号状态”。如果“<”字符后没有紧跟着“/”和对应的标签名,解析器会转换回“RCDATA状态”。这意味着在RCDATA元素标签的内容中(例如<textarea>或<title>的内容中),唯一能够被解析器认做是标签的就是“</textarea>”或者“</title>”。
理解:html除了认识自身的</textarea>”和“</title>”标签,其余的内在标签都不识别。
<textarea>是RCDATA元素(RCDATA elements),可以容纳文本和字符引用,注意不能容纳其他元素,HTML解码可以得到
<textarea><script>alert(5)</script></textarea>
但与问题4相同无法进入“标签开始状态”导致代码无法执行。
RCDATA元素下直接执行弹窗语句
<textarea><script>alert(6)</script></textarea>
执行结果

弹窗失败
原因:
对RCDATA有个特殊的情况。在浏览器解析RCDATA元素的过程中,解析器会进入“RCDATA状态”。在这个状态中,如果遇到“<”字符,它会转换到“RCDATA小于号状态”。如果“<”字符后没有紧跟着“/”和对应的标签名,解析器会转换回“RCDATA状态”。这意味着在RCDATA元素标签的内容中(例如<textarea>或<title>的内容中),唯一能够被解析器认做是标签的就是“</textarea>”或者“</title>”,其余的内在标签都不识别。
理解:html除了认识自身的</textarea>”和“</title>”标签,其余的内在标签都不识别。
基本元素下的语句进行html实体编码
<button onclick="confirm('7')">Button</button>
<button onclick="confirm('7')">Button</button>
执行结果:

弹窗成功
原因:由于首先先进行html解码所以语句解码为
<button onclick="confirm('7');">Button</button>
然后再执行js函数执行成功。
基本元素下的语句中的符号进行Unicode编码
<button onclick="confirm('8\u0027);">Button</button>
<button onclick="confirm('8');">Button</button>
执行结果:

点击按钮弹窗失败
原因:
onclick中的值会交给JS处理,在JS中只有字符串和标识符能用Unicode表示,' 显然不行,JS执行失败。
在JavaScript中,标识符只能包含字母或数字或下划线(“_”)或美元符号(“$”),且不能以数字开头。标识符与字符串不同之处在于字符串是数据,而标识符是代码的一部分。在 JavaScript 中,无法将标识符转换为字符串,但有时可以将字符串解析为标识符。
原始文本元素下的语句进行HTML实体编码
<script>alert(9);</script>
<script>alert(9)</script>
执行结果:

无弹窗
原因:
原始文本元素<script>,可以容纳文本,不能容纳字符引用,于是直接由JS处理,JS也认不出来,弹窗语句执行失败。
原始文本元素下的语句中的字符串进行Unicode编码
<script>\u0061\u006c\u0065\u0072\u0074(10);</script>
<script>alert(10)</script>
执行结果:

弹窗成功
原因:在JS中只有字符串和标识符能用Unicode表示,这里只有字符串进行了Unicode编码,而且在原始文本元素中不能容纳字符引用,但是可以容纳Unicode表示的字符串。
基本元素下语句全部进行Unicode编码
<script>\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0031\u0029</script>
<script>alert(11)</script>
执行结果:

弹窗失败
原因:同问题8在JS中只有字符串和标识符能用Unicode表示,这里的()非js标识符却进行了Unicode编码,js执行失败。
原始文本元素下的语句中的字符串进行Unicode编码
<script>\u0061\u006c\u0065\u0072\u0074(\u0031\u0032)</script>
<script>alert(12)</script>
执行结果:

弹窗失败
原因:
这里\u0031\u0032在解码的时候会被解码为字符串12,注意是字符串12,不是数字,字符串显然是需要引号的,JS执行失败。
这里给\u0031\u0032加上引号再进行执行


弹窗成功
基本元素下语句中符号的进行Unicode编码
<script>alert('13\u0027)</script>
<script>alert('13')</script>
执行结果:

弹窗失败
原因:同问题8这里的 ' 非js标识符却进行了Unicode编码,js执行失败。
基本元素下语句加入Unicode编码后的换行符
<script>alert('14\u000a')</script>
<script>alert('14\n')</script>
执行结果:

弹窗成功
原因:\u000a在JavaScript里是换行,就是\n,
代码实际形式
<script>alert('14\n')</script>
这里相当于在基本元素下没有进行编码,故可以正常弹窗。
将弹窗语句进行3次编码
<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(15)">aaaa</a>
执行结果:

原因:首先此语句符合HTML的解码顺序,首先先进行html解码,然后在进行url解码,最后进行js的Unicode解码
进行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(15)">aaaa</a>
<a href="javascript:alert(15)">aaaa</a>
首先他先解码出了js函数和冒号,交给了href的url模块,协议直接可以被识别,后面的部分都被解码成url编码的形式。
进行url解码后的语句
javascript:\u0061\u006c\u0065\u0072\u0074(15)
url编码解码后为Unicode编码形式,这里被Unicode编码的只有字符串,标识符及数字均未被编码。解码后交给js模块
进行Unicode解码后的语句
javascript:alert(15)
此协议可以直接被识别执行。
总结
要分清html元素,了解各个元素下可容纳的内容。防止无法识别导致的失败。例:原始文本元素<script>,可以容纳文本,不能容纳字符引用,但可以容纳js的Unicode表示
注意解码顺序,在不同的模块下看清模块需求。例:url在处理时会优先识别协议,在处理编码。
注意各种解码的需求。例:JS中只有字符串和标识符能用Unicode表示
注意解码后生成的结果是否能直接进行使用。例:Unicode解码后的数字会变成字符串使用时必须要加上引号。
注意在语句中加入编码后的符号,只要不影响原本的语句,都可以运行。
弹窗语句最好不要写在RCDATA元素下,html除了认识自身的RCDATA元素标签,其余的内在标签都不识别。
最好不要将间括号进行编码,否则<>被HTML解码后,不会进入标签开始状态,导致执行弹窗失败。