Encoding 两个字符似乎相同,但UTF-8编码不相同

Encoding 两个字符似乎相同,但UTF-8编码不相同,encoding,Encoding,我需要过滤一些非法字符串,如“密码”,但我发现有人绕过了我的检查程序。他们输入一个看起来完全是“密码”的字符串,但它并不相等。 我检查了它的Unicode,例如,“a”是8e61,而正常的“a”是61(十六进制)。 我的PHP文件编码、HTML元内容类型和MySQL编码都是utf-8 这是怎么发生的?为什么有视觉上相同的字符和不同的代码? 我想知道如何过滤这些字符。 我把奇怪的字符串放在这里,请复制它以便研究: 密码 由于某种原因,当我在这里复制有问题的“密码”时,它实际上显示了ASCII 1

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

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


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

我在“Password”上使用PHP函数bin2hex(),如下所示:

50c28e61c28e73c28e73c28e776fc28e72c28e64c28e
而正常的是:

50617373776f7264.
61
为简化起见,“a”的十六进制表示法为:

而正常的是:

50617373776f7264.
61
你可能看到的是所谓的同形文字(我不能确切地说,因为你问题的某些部分没有意义或不一致)。这些字符看起来相同或非常相似,因此乍一看可能会出错。为了避开你的支票,人们可以使用西里尔字母a,并且可以侥幸逃脱。但坦率地说,这实际上不是一个问题,因为我知道没有密码破解程序会尝试混合脚本,因为大多数密码都是ASCII码


至于原因,您可以看一看。

给定十六进制字符串
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(请参阅)。SS2没有定义的可见表示。该字符串明显不同于普通的“Password”。只要不去掉控制字符,就应该能够发现差异,因为字符串比较不应将其视为与普通的“密码”相同。

欢迎使用堆栈溢出。请尽快阅读这一页。欢迎来到Unicode的奇妙世界。有许多字符具有多种表示形式。对于半异国情调的示例,阿拉伯数字1被编码两次,一次用于西方阿拉伯U+0660,一次用于东方阿拉伯U+06F0,但符号相同;不同的是其他一些数字。看见你必须决定你是否要像对待U+0061一样对待U+8E61[…继续…][…继续…]等等;U+8E61是一个统一的汉族符号。您正在使用哪个代码页?0x8E61不是有效的UTF-8;0x8E是一个延续字节,0x61是拉丁文小写字母a,后面不能跟延续字节。你没有提供我们需要的所有信息;您正在处理的整个字节序列是什么?上面的注释仍然准确且或多或少相关,但您不太可能将U+8E61视为U+0061。我复制了您的字符串,并将其标识为包含:
0x0000:50 61 73 77 6F 72 64密码
。这是密码的常规ASCII表示形式。所以要么你的复制/粘贴没有保留奇怪的字符,要么我的没有。我在用Mac电脑。你能识别出你认为用十六进制表示的字节吗?(哦,U+0660和U+06F0是阿拉伯的零,而不是一;U+0661和U+06F1是一个。)@Jonathan Leffler,提供了十六进制字符串,谢谢!如何在PHP中删除此字符,或此类字符?我搜索了一些,如下所示,但他们无法删除此字符。我在此处找到了删除此字符的解决方案: