编码问题

0x01 编码发展史

  • 0x20以下的编码用作控制码,接下来一直到127号的的字节用来表示大小写字母,标点符号,空格,数字,这就是ascii码,只能满足美国人的需要。
  • 中国人民通过对 ASCII 编码的中文扩充改造,产生了 GB2312 编码,可以表示6000多个常用汉字。
  • 汉字实在是太多了,包括繁体和各种字符,于是产生了 GBK 编码,它包括了 GB2312 中的编码,同时扩充了很多。
  • 中国是个多民族国家,各个民族几乎都有自己独立的语言系统,为了表示那些字符,继续把 GBK 编码扩充为 GB18030 编码。
  • 每个国家都像中国一样,把自己的语言编码,于是出现了各种各样的编码,如果你不安装相应的编码,就无法解释相应编码想表达的内容。
  • 终于,有个叫 ISO 的组织看不下去了。他们一起创造了一种编码 UNICODE ,这种编码非常大,大到可以容纳世界上任何一个文字和标志。所以只要电脑上有 UNICODE 这种编码系统,无论是全球哪种文字,只需要保存文件的时候,保存成 UNICODE 编码就可以被其他电脑正常解释。
  • UNICODE 在网络传输中,出现了两个标准 UTF-8 和 UTF-16,分别每次传输 8个位和 16个位。
  • 于是就会有人产生疑问,UTF-8 既然能保存那么多文字、符号,为什么国内还有这么多使用 GBK 等编码的人?因为 UTF-8 等编码体积比较大,占电脑空间比较多,如果面向的使用人群绝大部分都是中国人,用 GBK 等编码也可以。但是目前的电脑来看,硬盘都是白菜价,电脑性能也已经足够无视这点性能的消耗了。所以推荐所有的网页使用统一编码:UTF-8。

0x02 各种编码

  • URL编码

一个百分号和该字符的ASCII编码所对应的2位十六进制数字,例如“/”的URL编码为%2F(一般大写,但不强求)

具体情况:

网址路径的编码,用的是utf-8编码
查询字符串的编码,用的是操作系统的默认编码
GET和POST方法的编码,用的是网页的编码
在Ajax调用中,IE总是采用GB2312编码(操作系统的默认编码),而Firefox总是采用utf-8编码。

escape()不能直接用于URL编码,它的真正作用是返回一个字符的Unicode编码值。比如"春节"的返回结果是%u6625%u8282,也就是说在Unicode字符集中,"春"是第6625个(十六进制)字符,"节"是第8282个(十六进制)字符。
它的具体规则是,除了ASCII字母、数字、标点符号"@ * _ + - . /"以外,对其他所有字符进行编码。在\u0000到\u00ff之间的符号被转成%xx的形式,其余符号被转成%uxxxx的形式。对应的解码函数是unescape()。
所以,"Hello World"的escape()编码就是"Hello%20World"。因为空格的Unicode值是20(十六进制)。

  • HTML实体编码

命名实体:以&开头,分号结尾的,例如“<”的编码是“<”

字符编码:十进制、十六进制ASCII码或unicode字符编码,样式为“&#数值;”,例如“<”可以编码为“<”和“<”

  • JS编码

js提供了四种字符编码的策略,

三个八进制数字,如果不够个数,前面补0,例如“e”编码为“\145”
两个十六进制数字,如果不够个数,前面补0,例如“e”编码为“\x65”
四个十六进制数字,如果不够个数,前面补0,例如“e”编码为“\u0065”
对于一些控制字符,使用特殊的C类型的转义风格(例如\n和\r)

  • CSS编码

用一个反斜线()后面跟1~6位的十六进制数字,例如e可以编码为“\65”或“65”或“00065”

  • 复合编码

所谓复合编码,也就是说输出的内容输出在多个环境中,例如

<td onclick=”openUrl(add.do?userName=’<%=value%>’);”>11</td>

value的内容首先出现在一个URL中,这个URL在一段javascript总,而javascript代码又是html的一部分。所以解码的顺序就是HTML解码–>js解码–>url解码,那么正确的编码顺序就应该是url编码–>js编码–>html编码。

0x03 浏览器解析

  • 浏览器解析HTML的步骤

浏览器收到从服务器发送来的HTML内容,会从头解析,当遇到<script></script>时,会调用javascript脚本解析器解析javascript,并执行脚本,然后继续解析其他的HTML内容,对于一些需要触发才能执行的事件,当触发事件发送时,脚本解析器才会解析其中的脚本,在事件触发之前,它是HTML的一部分。

  • 编码问题实例解析分析

1、URL编码"javascript:alert(1)"

 <a href="%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29"></a>
Answer: The javascript will NOT execute.

url不能对协议以及协议后的冒号进行编码,否则url解析器会认为其是无类型的。这里JavaScript是个伪协议,而且对javascript进行了url编码,会导致url解析器认为其是无类型,无法进行url解码。最终也就不会弹窗。

2、HTML字符实体编码 "javascript" 和 URL 编码 "alert(2)"

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

这里javascript属于html解析中的”属性值中的字符引用“,所以可以先被html解码,然后被url解析器识别出来,后面的alert(2)由于不是协议,url解析器可以正常解析,最后会弹窗。

3、URL 编码 ":"

  <a href="javascript%3aalert(3)"></a>
Answer: The javascript will NOT execute.

url不能对协议以及协议后的冒号进行编码,否则url解析器会认为其是无类型的。这里JavaScript是个伪协议,而且对javascript后的冒号进行了url编码,会导致url解析器认为其是无类型,无法进行url解码。最终也就不会弹窗。

4、HTML字符实体编码 < 和 >

  <div>&#60;img src=x onerror=alert(4)&#62;</div>
Answer: The javascript will NOT execute.

“<”和“>”字符被编码为“<”和“>”。当解析器解析完“<div>”并处于“数据状态”时,这两个字符将会被解析。当解析器遇到“&”字符,它会知道这是“数据状态的字符引用”,因此会消耗一个字符引用(例如“<”)并释放出对应字符的token。在这个例子中,对应字符指的是“<”和“>”。读者可能会想:这是不是意味着“<”和“>”的token将会被理解为标签的开始和结束,然后其中的脚本会被执行?答案是脚本并不会被执行。原因是解析器在解析这个字符引用后不会转换到“标签开始状态”。正因为如此,就不会建立新标签。因此,我们能够利用字符实体编码这个行为来转义用户输入的数据从而确保用户输入的数据只能被解析成“数据”。

5、HTML字符实体编码 < 和 >

  <textarea>&#60;script&#62;alert(5)&#60;/script&#62;</textarea>
Answer: The javascript will NOT execute AND the character entities will NOT be decoded either

在<textarea>和<title>标签中的字符引用会被HTML解析器解码,在解析这些字符引用的过程中不会进入“标签开始状态”,甚至在<textarea>和<title>的内容中都无法创建标签,更不会有javascript执行了。

6、<textarea>和<title>

<textarea><script>alert(6)</script></textarea>
Answer: The javascript will NOT execute.

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

7、HTML字符实体编码 " ' " (单引号)

<button onclick="confirm('7&#39;);">Button</button>
Answer: The javascript will execute.

html先将'解码为一个控制字符',闭合成功,然后javascript进行解析,最终执行。

8、Unicode编码 " ' " (单引号)

<button onclick="confirm('8\u0027);">Button</button>
Answer: The javascript will NOT execute.

javascript把uniocde\u0027解析为一个常量',而不是控制字符',所以无法闭合。
//像圆括号、双引号、单引号等等这些控制字符的unicode编码,在进行JavaScript解析的时候仅会被解码为字符串文本或者标识符名称

9、HTML字符实体编码 alert(9);

<script>&#97;&#108;&#101;&#114;&#116&#40;&#57;&#41;&#59</script>
Answer: The javascript will NOT execute.

在script块中的字符引用并不会被解析和解码,对于unicode字符视情况而定。

10、Unicode 编码 alert

<script>\u0061\u006c\u0065\u0072\u0074(10);</script>
Answer: The javascript will execute.

Unicode转义序列只有在标识符名称里不被当作字符串,也只有在标识符名称里的编码字符能够被正常的解析。当Unicode转义序列出现在标识符名称中时,它会被解码并解释为标识符名称的一部分,比如标识符alert,所以可以弹框。

11、Unicode 编码 alert(11)

<script>\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0031\u0029</script>
Answer: The javascript will NOT execute.

这里的unicode转义序列 (11) 不是标识符,所以无法正常解析,即无法弹窗。

12、Unicode 编码 alert 和 12

 <script>\u0061\u006c\u0065\u0072\u0074(\u0031\u0032)</script>
Answer: The javascript will NOT execute.

\u0031\u0032不会被解释为字符串常量(因为它们没有用引号闭合)

13、Unicode 编码 " ' " (单引号)

  <script>alert('13\u0027)</script>
Answer: The javascript will NOT execute.

这里\u0027没有被解析为控制字符,无法闭合,所以无法弹窗。
(当用Unicode转义序列来表示一个控制字符时,例如单引号、双引号、圆括号等等,它们将不会被解释成控制字符,而仅仅被解码并解析为标识符名称或者字符串常量。)

14、Unicode 编码换行符(0x0A)

  <script>alert('14\u000a')</script>
Answer: The javascript will execute.

这里会执行程序并弹窗,因为\u000a被解析成了换行字符文本,避免了因为换行符的出现而导致的javascript语法错误。

15、混合加密解析

<a href="&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3a;&#x25;&#x35;&#x63;&#x25;&#x37;&#x35;&#x25;&#x33;&#x30;&#x25;&#x33;&#x30;&#x25;&#x33;&#x36;&#x25;&#x33;&#x31;&#x25;&#x35;&#x63;&#x25;&#x37;&#x35;&#x25;&#x33;&#x30;&#x25;&#x33;&#x30;&#x25;&#x33;&#x36;&#x25;&#x36;&#x33;&#x25;&#x35;&#x63;&#x25;&#x37;&#x35;&#x25;&#x33;&#x30;&#x25;&#x33;&#x30;&#x25;&#x33;&#x36;&#x25;&#x33;&#x35;&#x25;&#x35;&#x63;&#x25;&#x37;&#x35;&#x25;&#x33;&#x30;&#x25;&#x33;&#x30;&#x25;&#x33;&#x37;&#x25;&#x33;&#x32;&#x25;&#x35;&#x63;&#x25;&#x37;&#x35;&#x25;&#x33;&#x30;&#x25;&#x33;&#x30;&#x25;&#x33;&#x37;&#x25;&#x33;&#x34;&#x28;&#x31;&#x35;&#x29;"></a>
Answer: The javascript will execute.

(1)先经过html解析(题目2,属性值中的字符引用,正常解析)

<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)"></a>

(2)然后url解析(依旧题目2,url解析的内容为非协议内容,正常解析)

<a href="javascript:\u0061\u006c\u0065\u0072\u0074(15)"></a>

(3)unicode解析(题目10,unicode转义字符出现在标识符名称中,正常解析)

<a href="javascript:alert(15)"></a>

(4)最后语法正确,javascript正常解析并弹窗。(当然,这里需要在</a>前面随便加点字符,不然无法显示并弹窗)

资料索引:
对于xss等有关的html,url,unicode编码做的一个小总结
深入理解浏览器解析机制和XSS向量编码
浏览器编码流程
從XSS理解編碼解析原理
网页编码就是那点事

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容

  • 编码问题一直困扰着开发人员,尤其在 Java 中更加明显,因为 Java 是跨平台语言,不同平台之间编码之间的切换...
    x360阅读 2,480评论 1 20
  • 一、常见的编码方式 (1)ASCII码这是最简单的一种编码方式。这种编码方式总共可以表示128个字符,其中包括控制...
    周二鸭阅读 3,203评论 0 0
  • XSS与字符编码基本介绍: 提起XSS 想到的就是插入字符字符编码与各种解析了!现在介绍一下在xss中最经常用到的...
    BerL1n阅读 2,038评论 0 2
  • 作者:amnesiac 首发:官方论坛之中文版 编码是每个脚本人、程序员最常见的困惑之一(中文用户尤其常遇),在 ...
    amnesiac阅读 1,419评论 0 3
  • 细腻而又不舍的手, 温暖了幼嫩的脊背 在柳絮飘浮的念叨里 谁的容颜迟暮? 谁的步幅婆娑? 没有怀念不了的过去 只有...
    叁栀桦阅读 298评论 0 8