regex 总览待审核
安全 · 同形混淆 UTS #39

同形字:看着是 apple.com,其实是 аpple.com

Cyrillic а(U+0430)和 Latin a(U+0061)字形一模一样,码点完全不同。攻击者用这类「孪生字」拼出和真品牌 / 真域名肉眼无异的字符串(homograph attack)。Unicode 用 UTS #39 来防:一张 confusables 表把孪生字折叠成统一 skeleton、再加混合脚本检测。这页和 bidi 页的 Trojan Source 是「看不见的攻击面」的两面。

本页内嵌的是 UTS #39 confusables 数据的一个精选子集(覆盖 Cyrillic / Greek / 数字等常见 Latin 孪生字),用于演示算法,不是完整表。生产环境请用完整的 confusables.txt 或 ICU USpoofChecker

一对孪生:同一个形,两个码点

左右两个「a」肉眼无法区分,码点和所属 Script 却不同。=== 直接判不等 —— 但用户看不出来:

探针:逐码点验明正身 + 混合脚本检测

输入一个字符串,逐 code point 标出字形、码点与 Script。当一个串里混了多种文字系统(典型如 Latin 里掺 Cyrillic),几乎可以肯定是冒充 —— 正常单词不会这么写。掺进来的、与主文字不同的码点会被标红:

skeleton 算法:把孪生字折叠到同一形

UTS #39 的判定思路:把每个字符按 confusables 表映射到它的「代表字」,得到 skeleton;两个串视觉可混淆当且仅当它们的 skeleton 相同。下面对左右两个串各算 skeleton 并比较 —— 默认放真 paypal 和掺了 Cyrillic 的 pаypаl:

IDN 与 punycode:域名其实只能是 ASCII

域名系统只认 ASCII,非 ASCII 域名靠 punycode(xn-- 前缀)编码后传输。浏览器地址栏可能显示成好看的 Unicode,底层解析的却是 punycode。输入一个域名,看浏览器(URL 解析器走 IDNA)实际拿到的 host —— 掺了 Cyrillic 的域名会变成一串完全不同的 xn--:

一句话收束:凡是要拿来当标识的字符串(用户名 / 域名 / 包名 / 显示名),都要防同形冒充:先 normalize(NFKC) 折掉兼容变体,再按 UTS #39 算 skeleton 查重、做混合脚本检测。这和 bidi 控制符一样,属于「字符串看着没问题、机器看到的另有玄机」的安全面。Script 属性的来历见 \p{…} 属性类那页