一、HTML与JavaScript自解码机制
JavaScript代码出现在HTML标签内,意味着这段JavaScript可以进行HTML形式的编码,这种编码有以下两种:
- 进制编码:&#xH;(十六进制格式)、&#D;(十进制格式),最后分号可以不要。
- HTML实体编码。
在JavaScript执行之前,HTML形式的编码会自动解码。
如下:
<input type="button" id='exec_btn' value='exec' οnclick="document.write('<img src=@   onerror=alert(123)  />')" />
等同于:
<input type="button" id='exec_btn' value='exec' οnclick="document.write('<img src=@ οnerrοr=alert(123) />')" />
等同于:
<input type="button" id='exec_btn' value='exec' οnclick="document.write('<img src=@ οnerrοr=alert(123) />')" /
如果用户输入出现在<script>标签里的JavaScript中,需要遵循JavaScript编码,有如下几种形式:
- Unicode形式:\uH(十六进制)。
- 普通十六进制:\xH。
- 纯转义:\'、\"、\<、\>这样在特殊字符之前加\进行转义。
<input type="button" id='exec_btn' value='exec' />
<script>
var obtn = document.getElementById('exec_btn')
obtn.onclick = function() {
document.write('\u003c\u0069\u006d\u0067\u0020\u0073\u0072\u0063\u003d\u0040\u0020\u0020\u0020\u006f\u006e\u0065\u0072\u0072\u006f\u0072\u003d\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0032\u0033\u0029\u0020\u002f\u003e')
//document.write('<img src=@ onerror=alert(123) />')
}
</script>
二、浏览器进制常识
在浏览器常用的进制混淆有八进制,十进制和十六进制。
HTML属性最常用的属性为十进制和十六进制。十进制在HTML中使用8来表示,用&和#作为前缀,中间为十进制数字,以(;)结尾,也可以没有。如果十六进制则用Z表示,比十进制多了x,进制码也多了a~f字符来表示。x,a-f这几个字符对大小写不敏感。
CSS中也只能用到十进制和十六进制,CSS兼容HTML中的进制表示形式,十六进制还可以使用\6c形式表示,用斜线作为进制数值表示。
JavaScript中eval执行的字符串有八进制和十六进制分别用\56与\x5c表示。但是不能直接给诸如汉字的多字节编码,只能使用Unicode编码。
JavaScript自身带有两个函数可以进行进制编码与解码:char.toString(jinzhi)、String.fromCharCode(code, jinzhi)。
三、浏览器编码常识
在JavaScript中有三套编码解码函数,分别为:
escape/unescape
encodeURI/decodeURI
encodeURIComponent/decodeURIComponent
escape不编码的字符有69个:
*、+、-、.、/、@、_、0~9、a~z、A~Z
而且escape对0~255以外的unicode值进行编码时输出 %u**** 格式。
encodeURI不编码的字符有82个:
!、#、$、&、'、(、)、*、+、,、-、.、/、:、;、=、?、@、_、~、0~9、a~z、A~Z
encodeURIComponent不编码的字符有71个:
!、'、(、)、*、-、.、_、~、0~9、a~z、A~Z
除了JavaScript提供的这三种加密解密方法,我们还需要了解HTMLEncode、URLEncode、JSEncode、UTF-7编码、Base64编码