算法与数据结构 / regex · Unicode 字符模型与一个自研引擎 / 同形字:看着是 apple.com 待审核 27 / 36
安全 · 同形混淆 UTS #39

同形字:看着是 apple.com

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

1 · 一对孪生

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

图 1-1 · 拉丁 a 与西里尔 а 的字形、码点对照,以及两者的相等判定。

2 · 混合脚本检测

一个串里若混了多种文字系统,典型如拉丁里掺西里尔,几乎可以断定是冒充:正常单词不会这么写。逐码点标出 Script,与主文字不同的那些标红,是最省事的一道检查。

图 2-1 · 逐码点的字形、码点与 Script 标注,掺入的异种脚本标红,下方给出混合脚本判定。可改输入或点预设。

3 · skeleton 折叠

UTS #39 的判定思路是把每个字符按 confusables 表映射到代表字,得到 skeleton;两个串视觉可混淆,当且仅当 skeleton 相同。真 paypal 与掺了西里尔的 pаypаl 码点不同、skeleton 相同,冒充就是这么成立的。

图 3-1 · 两个字符串各算 skeleton 并比较,同时给出直接相等与 skeleton 相等两个判定。可改两侧输入。

警示 · 本页内嵌的是 confusables 数据的一个精选子集,覆盖常见的西里尔、希腊与全角孪生字,用于演示算法。生产环境要用完整的 confusables.txt 或 ICU 的 USpoofChecker,那里还包含多字符映射与更细的限制级别。

4 · IDN 与 punycode

域名系统只认 ASCII,非 ASCII 域名靠 punycode 编码后传输,前缀是 xn--。地址栏可能显示成好看的 Unicode,底层解析的却是那串编码——两个长得一样的域名,punycode 完全不同。

图 4-1 · 一个域名经浏览器 URL 解析器(走 IDNA)之后的真实 host。可改域名或点预设。

建议 · 凡是拿来当标识的字符串——用户名、域名、包名、显示名——都要防同形冒充:先 归一化 折掉兼容变体,再按 UTS #39 算 skeleton 查重、做混合脚本检测。Script 属性的来历见 \p{…} 属性类

5 · 参考文献

  1. Unicode. UTS #39: Unicode Security Mechanisms. skeleton 算法、混合脚本限制级别与 confusables 数据的定义。unicode.org
  2. Unicode. confusables.txt. 孪生字到代表字的完整映射表,本页内嵌的是它的子集。unicode.org
  3. Unicode. UTS #46: Unicode IDNA Compatibility Processing. 域名的 Unicode 处理与 punycode 转换规则。unicode.org
  4. MDN. URL. 本页用来取真实 host 的接口,其解析走 IDNA。developer.mozilla.org