golang中的utf8第二个字节下限

时间:2017-12-12 09:48:29

标签: go unicode utf-8

我最近经历了utf8解码的go源代码。 显然,当解码utf8字节时,第一个字节的值为224 (0xE0)它映射到[0xA0;为0xBF。 https://github.com/golang/go/blob/master/src/unicode/utf8/utf8.go#L81 https://github.com/golang/go/blob/master/src/unicode/utf8/utf8.go#L94

如果我正确理解utf8规范(https://tools.ietf.org/html/rfc3629),则每个连续字节的最小值为0x80或1000 0000.为什么打开0xE0的字节的最小值更高,即0xA0而不是0x80?

2 个答案:

答案 0 :(得分:4)

原因是为了防止所谓的过长序列。引用RFC:

  

上面的解码算法的实现必须防止      解码无效序列。例如,一个天真的实现可能      将超长UTF-8序列C0 80解码为字符U + 0000 ,      或代理对ED A1 8C ED BE B4进入U + 233B4。解码      无效序列可能会产生安全后果或导致其他后果      问题。

     

[...]

     

可以针对这种攻击进行特别微妙的攻击      一个解析器,它执行安全关键的有效性检查      UTF-8编码形式的输入,但解释某些非法八位字节      序列作为字符。例如,解析器可能会禁止      编码为单八位字节序列00时的NUL字符,但是      错误地允许非法的两个八位字节序列C0 80并解释      它是一个NUL角色。另一个例子可能是解析器      禁止八位字节序列2F 2E 2E 2F(“/../”),但允许      非法八位字节序列2F C0 AE 2E 2F。最后一次攻击有      实际上已被广泛用于攻击Web服务器的病毒      2001;因此,安全威胁是非常真实的。

另请注意第4节中的语法规则,它明确地仅允许在E0之后的字符A0-BF:

UTF8-2      = %xC2-DF UTF8-tail  
UTF8-3      = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
              %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )  
UTF8-4      = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
              %xF4 %x80-8F 2( UTF8-tail )

答案 1 :(得分:1)

如果UTF-8序列的第一个字节是0xe0,这意味着它是一个3字节序列,表示/编码Unicode代码点(因为0xe0 = 1110 0000b)。

Wikipedia: UTF-8:

Number    Bits for    First       Last        Byte 1   Byte 2    Byte 3 
of bytes  code point  code point  code point 
---------------------------------------------------------------------------
3         16          U+0800      U+FFFF      1110xxxx 10xxxxxx  10xxxxxx

使用3字节UTF-8序列编码的第一个Unicode代码点是U + 0800,因此代码点为0x0800,二进制:0000 1000 0000 0000

如果您尝试将这些位插入标有x的那些位:

1110xxxx 10xxxxxx 10xxxxxx
11110000 10100000 10000000

如您所见,第二个字节为1010 0000,即0xa0。所以一个以0xe0开头的有效UTF-8序列:它的第二个字节不能低于0xa0(因为即使是UTF-8编码序列以0xe0开头的最低Unicode码点也有一个0xa0)的第二个字节。