12.5. Unicode¶
12.5.1. 基本概念¶
12.5.1.1. BMP¶
BMP (Basic Multilingual Plane),译作基本多文种平面,是Unicode中的一个编码区块。
12.5.1.2. 码平面¶
Unicode编码点分为17个平面(plane),每个平面包含2^16(即65536)个码位。17个平面的码位可表示为从U+xx0000到U+xxFFFF,其中xx表示十六进制值从0016到1016,共计17个平面。
12.5.1.3. Code Point¶
Code Point也被称作Code Position,译作码位或编码位置,是指组成代码空间的数值。
12.5.1.4. Code Unit¶
指某种 Unicode 编码方式里编码一个 Code Point 需要的最少字节数,比如 UTF-8 需要最少一个字节,UTF-16 最少两个字节,UCS-2 两个字节,UCS-4 和 UTF-32 四个字节。
12.5.1.5. Surrogate Pair¶
Surrogate Pair 是用于 UTF-16 的以向后兼容 UCS-2 的,做法是取 UCS-2 范围里的 0xD800~0xDBFF (称为 high surrogates) 和 0xDC00~0xDFFF (称为 low surrogates) 的码位,一个 high surrogate 接一个 low surrogate 拼成四个字节表示超出 BMP 的字符,两个 surrogate range 都是 1024 个码位,所以 surrogate pair 可以表达 1024 x 1024 = 1048576 = 0x100000 个字符。
12.5.1.6. Combining Character¶
例如 He̊llö
含有重音符号之类的字符,进行组合会使用大量的码位。所以这种字符多用组合的方式来实现。
12.5.1.7. BOM¶
字节顺序标记(byte-order mark,BOM)是一个有特殊含义的统一码字符,码点为 U+FEFF
。当以UTF-16或UTF-32来将UCS字符所组成的字符串编码时,这个字符被用来标示其字节序。常被用于区分是否为UTF编码。
12.5.2. 编码方式¶
12.5.2.1. UCS-2¶
UCS-2 (2-byte Universal Character Set)是一种定长的编码方式,UCS-2仅仅简单的使用一个16位码元来表示码位,也就是说编码范围在0到0xFFFF的码位范围内。
12.5.2.2. UTF-8¶
UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,也是一种前缀码。它可以用一至四个字节对Unicode字符集中的所有有效编码点进行编码,属于Unicode标准的一部分。编码方式如下
码点的位数 |
码点起值 |
码点终值 |
字节序列 |
Byte 1 |
Byte 2 |
Byte 3 |
Byte 4 |
Byte 5 |
Byte 6 |
---|---|---|---|---|---|---|---|---|---|
7 |
U+0000 |
U+007F |
1 |
0xxxxxxx |
|||||
11 |
U+0080 |
U+07FF |
2 |
110xxxxx |
10xxxxxx |
||||
16 |
U+0800 |
U+FFFF |
3 |
1110xxxx |
10xxxxxx |
10xxxxxx |
|||
21 |
U+10000 |
U+1FFFFF |
4 |
11110xxx |
10xxxxxx |
10xxxxxx |
10xxxxxx |
||
26 |
U+200000 |
U+3FFFFFF |
5 |
111110xx |
10xxxxxx |
10xxxxxx |
10xxxxxx |
10xxxxxx |
|
31 |
U+4000000 |
U+7FFFFFFF |
6 |
1111110x |
10xxxxxx |
10xxxxxx |
10xxxxxx |
10xxxxxx |
10xxxxxx |
12.5.2.3. UTF-16¶
UTF-16 (16-bit Unicode Transformation Format)是UCS-2的拓展,用一个或者两个16位的码元来表示码位,可以对0到0x10FFFF的码位进行编码。
12.5.3. 等价性问题¶
12.5.3.1. 简介¶
Unicode(统一码)包含了许多特殊字符,为了使得许多现存的标准能够兼容,提出了Unicode等价性(Unicode equivalence)。在字符中,有些在功能上会和其它字符或字符序列等价。因此,Unicode将一些码位序列定义成相等的。
Unicode提供了两种等价概念:标准等价和兼容等价。前者是后者的一个子集。例如,字符n后接着组合字符 ~ 会(标准和兼容)等价于Unicode字符ñ。而合字ff则只有兼容等价于两个f字符。
Unicode正规化是文字正规化的一种形式,是指将彼此等价的序列转成同一列序。此序列在Unicode标准中称作正规形式。
对于每种等价概念,Unicode又定义两种形式,一种是完全合成的,一种是完全分解的。因此,最后会有四种形式,其缩写分别为:NFC、NFD、NFKC、NFKD。对于Unicode的文字处理程序而言,正规化是很重要的。因为它影响了比较、搜索和排序的意义。
12.5.3.2. 标准等价¶
统一码中标准等价的基础概念为字符的组成和分解的交互使用。合成指的是将简单的字符合并成较少的预组字符的过程,如字符n和组合字符 ~ 可以组成统一码ñ。分解则是反向过程,即将预组字符变回部件。
标准等价是指保持视觉上和功能上的等价。例如,含附加符号字母被视为和分解后的字母及其附加符号是标准等价。换句话说,预组字符‘ü’和由‘u’及 ‘¨’所组成的序列是标准等价。相似地,统一码统合了一些希腊附加符号和外观与附加符号类似的标点符号。
12.5.3.3. 兼容等价¶
兼容等价的范围较标准等价来得广。如果序列是标准等价的话就会是兼容等价,反之则未必对。兼容等价更关注在于纯文字的等价,并把一些语义上的不同形式归结在一起。
例如,上标数字和其所使用的数字是兼容等价,但非标准等价。其理由为下标和上标形式虽然在某些时侯属于不同意义,但若应用程序将他们视为一样也是合理的(虽然视觉上可区分)。如此,在统一码富文件中,上标和下标就可以以比较不累赘地方式出现(见下一节)。
全角和半角的片假名也是一种兼容等价但不是标准等价。如同合字和其部件序列。其只有视觉上但没有语义上的区别。换句话说,作者通常没有特别宣称使用合字是一种意思,而不使用是另一种意思。相对地,这尽限于印刷上的选择。
文字处理软件在实现统一码字符串的搜索和排序时,须考虑到等价性的存在。如果没有此特性的话,用户在搜索时将无法找到在视觉上无法区分的字形。
统一码提供了一个标准的正规化算法,可将所有相同的序列产生一个唯一的序列。 其等价准绳可以为标准的(NF)或兼容的(NFK)。 既然可以任意选择等价类中的元素,对每一个等价标准有多个标准形式也是有可能的。 统一码为每一种等价准绳分别提供两种正规形式:合成用的NFC和NFKC以及分解用的NFD和NFKD。 而不论是组合的或分解的形式,都会使用标准顺序,以此限制正规形式只有唯一形式。
12.5.3.4. 正规化¶
为了比较或搜索统一码字符串,软件可以使用合成或分解形式其中之一。 只要被比较或搜索的字符串使用的形式是相同的,哪种选择都没关系。 另一方面,等价概念的选择则会影响到搜索结果。 譬如,有些合字如ffi(U+FB03)、罗马数字如Ⅸ(U+2168),甚至是上标数字如⁵(U+2075)有其个别统一码码位。 标准正规形式并不会影响这些结果。 但兼容正规形式会分解ffi成f、f、i。所以搜索U+0066(f)时,在NFKC中会成功,但在NFC则会失败。 同样地有在预组罗马数字Ⅸ 中搜索拉丁字母I(U+0049)。类似地,“⁵”会转成“5”。
对于浏览器,将上标转换成到基下划线未必是好的,因为上标的信息会因而消失。为了允许这种不同,统一码字符数据库句含了兼容格式标签,其提供了兼容转换的细节。在合字的情况下,这个标签只是 <compat>
,而在上标的情况下则为 <super>
。丰富文件格式如超文本置标语言则会使用兼容标签。例如,HTML使用自定义标签来将“5”放到上标位置。
12.5.3.5. 正规形式¶
NFD Normalization Form Canonical Decomposition 以标准等价方式来分解
NFC Normalization Form Canonical Composition 以标准等价方式来分解,然后以标准等价重组之。若是singleton的话,重组结果有可能和分解前不同。
NFKD Normalization Form Compatibility Decomposition 以兼容等价方式来分解NFKC
Normalization Form Compatibility Composition 以兼容等价方式来分解,然后以标准等价重组之
12.5.4. Tricks¶
部分语言的长度并不是字符的长度,一个UTF-16可能是两位。
部分语言在翻转UTF-16等多字节编码时,会处理错误。
12.5.5. 安全问题¶
12.5.5.1. Visual Spoofing¶
例如bаidu.com(此处的a为u0430)和baidu.com(此处的a为x61)视觉上相同,但是实际上指向两个不同的域名。
baidu.com(此处的a为uff41)和baidu.com(此处的a为x61)有一定的不同,但是指向两个相同的域名。
这种现象可以引起一些Spoofing或者WAF Bypass的问题。
12.5.5.2. Best Fit¶
如果两个字符前后编码不同,之前的编码在之后的编码没有对应,程序会尝试找最佳字符进行自动转换。
当宽字符变成了单字节字符,字符编码会有一定的变化。
这种现象可能引起一些WAF Bypass。
12.5.5.3. Syntax Spoofing¶
以下四个Url在语法上看来是没问题的域名,但是用来做分割的字符并不是真正的分割字符,而是U+2044( ⁄ ),可以导致一些UI欺骗的问题。
http://macchiato.com/x.bad.com macchiato.com/x bad.com
http://macchiato.com?x.bad.com macchiato.com?x bad.com
http://macchiato.com.x.bad.com macchiato.com.x bad.com
http://macchiato.com#x.bad.com macchiato.com#x bad.com
12.5.5.4. Punycode Spoofs¶
http://䕮䕵䕶䕱.com http://xn–google.com
http://䁾.com http://xn–cnn.com
http://岍岊岊岅岉岎.com http://xn–citibank.com
有些浏览器会直接显示puncode,但是也可以借助这种机制实现UI Spooof。
12.5.5.5. Buffer Overflows¶
在编码转换的时候,有的字符会变成多个字符,如Fluß → FLUSS → fluss这样可能导致BOF。
12.5.6. 常见载荷¶
12.5.6.1. URL¶
‥
(U+2025)︰
(U+FE30)。
(U+3002)⓪
(U+24EA)/
(U+FF0F)p
(U+FF50)ʰ
(U+02B0)ª
(U+00AA)
12.5.6.2. SQL注入¶
'
(U+FF07)"
(U+FF02)﹣
(U+FE63)
12.5.6.3. XSS¶
<
(U+FF1C)"
(U+FF02)
12.5.6.4. 命令注入¶
&
(U+FF06)|
(U+FF5C)
12.5.6.5. 模板注入¶
﹛
(U+FE5B)[
(U+FF3B)