什么是Homoglyph?揭秘25个你没见过的字母A——homoglyph同形字符检测完整入门
【免费下载链接】homoglyphA big list of homoglyphs and some code to detect them项目地址: https://gitcode.com/gh_mirrors/ho/homoglyph
**homoglyph(同形字符)**是那些"长得几乎一模一样、却拥有不同 Unicode 编码"的字符。开源项目homoglyph正是一份大规模的同形字符数据表 + 一套可直接用于生产的检测代码:它能识别被同形字符伪装过的单词(比如把credit写成ϲrEd1ᴛ),常用于敏感词过滤、内容审核和安全防护。本文将带你从零认识同形字符,并快速上手这套检测工具。
一、25 个"字母 A":同形字符到底长什么样?
先来看一段"迷惑性极强"的文本(同一字体渲染,肉眼几乎无法区分):
A Α А Ꭺ ᗅ ᴀ ꓮ A 𐊠 𝐀 𝐴 𝑨 𝒜 𝓐 𝔄 𝔸 𝕬 𝖠 𝗔 𝘈 𝘼 𝙰 𝚨 𝛢 𝜜 𝝖 𝞐这 25 个字符全都"看起来像大写字母 A",但它们的 Unicode 编码点各不相同——分别来自拉丁文、希腊文、西里尔文、切罗基文、加拿大原住民音节文字、全角字符、哥特文以及数学符号。👀
同形字符的"危害"不在于混淆,而在于绕过:
| 场景 | 同形字符如何制造问题 |
|---|---|
| 敏感词过滤 | 把黑名单中的单词替换成同形字符,机器匹配不到,人却能看懂 |
| 用户名/域名仿冒 | 用西里尔字母а冒充拉丁a,做出肉眼相同的假账号、假网址 |
| 代码审计 | 在源码中混入同形字符,让0变成Ο,埋下隐蔽 bug |
二、项目结构一览:数据 + 检测双管齐下
homoglyph 项目的组织非常清晰,克隆仓库后即可按路径快速定位资源:
git clone https://gitcode.com/gh_mirrors/ho/homoglyph主要模块如下:
raw_data/chars.txt—— 核心数据表:1860 行,每行是一组互为同形的字符,例如其中一行就是上面 25 个"字母 A"raw_data/char_codes.txt—— 同一份数据,但用 16 进制 Unicode 编码点表示,方便程序解析javascript/src/homoglyph.js—— 零依赖的 JavaScript 同形字符搜索函数node/index.js—— 封装成 Node.js 模块的入口(即 npm 包homoglyph-search)src/main/java/net/codebox/homoglyph/Homoglyph.java—— Java 版检测类,支持从 Maven 引入generator/main.py—— Python 生成脚本:解析原始数据文件,自动重新生成上述所有数据与代码文件
这种"一份数据、多语言产出"的设计,正是它的巧妙之处。
三、3 行代码跑通检测:JavaScript 快速上手
1. 一键安装
在node/目录下,模块已打包为 npm 包,直接安装:
npm install homoglyph-search2. 调用 search() 检测
以仓库自带的示例 node/example/example.js 为例,逻辑只有三行:
var homoglyphSearch = require('homoglyph-search'); var textToSearch = 'Get free ϲrEd1ᴛ'; // 被同形字符伪装的文本 var bannedWords = ['credit']; // 要检测的单词 var result = homoglyphSearch.search(textToSearch, bannedWords); console.log(result);输出会告诉你:文本中确实藏着一个伪装版credit,并返回匹配的原文片段、目标单词和起始位置。也就是说,ϲ(希腊小写字母)、1(数字一)、ᴛ(数学粗体 t)组成的"假词"逃不过它的法眼。🎯
3. Java 版本同样简单
Java 侧通过 Maven 引入后,使用HomoglyphBuilder.build()构建对象,再调用search(textToSearch, bannedWords)即可,返回结果列表结构与 JS 版一致。源码见src/main/java/net/codebox/homoglyph/Homoglyph.java。
四、底层原理:一张巨大的"字符映射表"
打开 node/index.js 就能看懂核心机制:模块内置了一个CHAR_MAP映射表,把每个标准字符映射到它的所有"替身",例如:
"0": ["𝟘", "0", "⓪", ...], // 数字 0 的 80 多个同形替身 "A": ["Α", "А", "Ꭺ", "𝐀", ...] // 字母 A 的 26 个同形替身检测流程是三步:
- 拆字符:把待检文本按 Unicode 码位逐个拆开(这里刻意绕开了 JS 字符串的
.length陷阱) - 逐位比对:对目标单词的每个位置,判断文本字符是否与标准字符相等、或在其"替身列表"中
- 滑窗扫描:从左到右滑动窗口,收集所有命中位置并返回
generator/目录下的 Python 脚本负责维护这张表:data_file_parser.py解析generator/source_data/confusables.txt(源自 Unicode 官方混淆字符表并补充了额外条目),再由output_chars.py、output_char_codes.py、output_js.py等脚本统一输出各格式文件。想扩充数据?改源头、跑一次main.py即可全量再生成。
五、新手必知的两个 Unicode 坑 ⚠️
这个项目的 README 特别强调了同形字符检测绕不开的两个"语言级陷阱":
JavaScript 的长度陷阱
> 'FOUR'.length 4 > '𐊇𐊒𝐔𝐑'.length 8 // 同样的 4 个字符,长度却翻倍!代码位高于 U+FFFF 的字符在 JS 字符串中会占用 2 个 UTF-16 单元。本项目因此使用 ES6 的for...of循环来逐字符遍历,保证拆分正确。
Java 的 16 位 char 陷阱
Java 的char类型只有 16 位,无法表示高码位字符,.length()同样会"数错"。项目中的 Java 实现改用int表示码位值,正确处理这类高值字符。
💡 小结:只要你的检测逻辑依赖
length或按字节/单元遍历字符串,在同形字符面前都会翻车。
六、如何验证检测能力?跑一遍内置测试
项目自带了覆盖全映射表的测试数据,可以直观看到"哪些伪装能被识别":
javascript/tests/js/tests/DataTests.js+DataTestsRunner.html:浏览器里跑 Jasmine 测试,逐字符验证每个同形替换都能命中node/test/spec/JSTests.js:命令行回归测试,例如验证search('UNIT T35TING', ['TEST'])能定位到第 5 位的伪装词T35T
cd node && npm test跑通测试,你就拥有了一套"可审计"的检测工具。✅
七、总结:一文记住 homoglyph 同形字符检测
- 同形字符是 Unicode 时代"形同而码不同"的字符,是敏感词过滤绕过的经典手法
- homoglyph 项目提供 1860 组同形字符数据(
raw_data/)+ JS/Java 双语言检测实现 + Python 数据生成器 - 使用只需两步:安装
homoglyph-search,调用search(文本, 目标词列表) - 检测的核心是一张"字符 → 替身列表"的映射表,配合正确的码位遍历即可
- 警惕 JS 与 Java 在高码位字符上的长度陷阱,这是新手最容易踩的坑
无论你是做内容安全、风控审核,还是仅仅想弄懂 Unicode 的"暗面",这份数据表加这两个库,都足够你迈出同形字符检测的第一步。
【免费下载链接】homoglyphA big list of homoglyphs and some code to detect them项目地址: https://gitcode.com/gh_mirrors/ho/homoglyph
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考