两个字符看起来完全相同,但UTF-8编码不相同

时间:2013-07-16 03:53:23

标签: encoding

我需要过滤一些非法字符串,比如“密码”,但我发现有人绕过了我的支票程序。他们输入一个看起来完全是“密码”的字符串,但它不相等。 我检查了它的Unicode,例如,“a”是8e61,而正常的“a”是61(十六进制)。 我的PHP文件的编码,HTML元内容类型和MySQL编码都是utf-8。

这是怎么发生的?为什么视觉上相同的字符和不同的代码? 我想知道如何过滤这些字符。 我把奇怪的字符串放在这里,请复制它用于研究: 密码


出于某种原因,我在这里复制了有问题的“密码”,它实际上显示了ASCII。

我在“密码”上使用PHP函数bin2hex(),并得到以下内容:

50c28e61c28e73c28e73c28e776fc28e72c28e64c28e

而正常的是:

50617373776f7264.

为简化起见,“a”的十六进制表示为:

c28e61

而正常的是:

61

2 个答案:

答案 0 :(得分:1)

给定十六进制字符串50c28e61c28e73c28e73c28e776fc28e72c28e64c28e,您有一个有效的UTF-8字符串的编码:

0x50      = U+0050 = P
0xC2 0x8E = U+008E = SS2
0x61      = U+0061 = a
0xC2 0x8E = U+008E = SS2
0x73      = U+0073 = s
0xC2 0x8E = U+008E = SS2
0x73      = U+0073 = s
0xC2 0x8E = U+008E = SS2
0x77      = U+0077 = w
0x6F      = U+006F = o
0xC2 0x8E = U+008E = SS2
0x72      = U+0072 = r
0xC2 0x8E = U+008E = SS2
0x64      = U+0064 = d
0xC2 0x8E = U+008E = SS2

0xC2 0x8E序列映射到ISO 8859-1 0x8E,它是一个控制字符SS2或单个移位2(见Unicode Code Charts)。 SS2没有定义的可见表示。该字符串明显不同于普通的“密码”。只要您不删除控制字符,您就应该能够发现差异,因为字符串比较不应该将其视为与普通“密码”相同。

答案 1 :(得分:0)

你可能会看到什么(我无法确切地说,因为你的问题的某些部分没有意义或不一致)是所谓的 homoglyphs 。这些字符看起来相同或非常相似,因此乍一看可能会出错。为了规避您的检查,人们可以使用西里尔语 a 并侥幸逃脱。但坦率地说,这实际上并不是一个问题,因为我知道没有密码破解者实际上会尝试混合脚本,因为大多数密码都是纯ASCII的。

至于 why ,您可以查看Why are there duplicate characters in Unicode?