隐形字符检测¶
为什么文字里会有看不见的东西¶
文件外流追踪¶
机构要发一份文件给二十个人,于是准备二十份副本,每一份在不同的位置插入不同组合的零宽字符。内容看起来完全一样,打印出来也一样,复制粘贴到别的地方那些字符还是跟着走。文件外流之后,比对一下就知道是哪一份流出去的。
要转发手上的文件之前,先扫一遍。
钓鱼网址¶
аpple.com 跟 apple.com 看起来一样,前者的第一个字母是西里尔文的 а。域名注册商对混用字母的防范不一致,而人眼分辨不出来。
代码里的方向覆写¶
在源代码里放一个右至左覆写字符,人在编辑器里看到的顺序跟编译器读到的可以完全不同。注释看起来包住了一段代码,实际上没有。这类手法有个名字叫 Trojan Source。
几个真的会遇到的场景¶
记者收到爆料之后的查证动作¶
记者取得一份内部文件,向该机构查证是专业要求。查证时最自然的动作是出示文件,或引用其中一段精确的文字问「这一段是不是真的」。
如果文件是二十份带不同标记的副本之一,出示或引用查证等于把消息来源交给正在找他的人。每一步都做得很专业,来源却在查证那一刻被烧掉。
处理顺序:
- 收到文件先扫,别急着读完
- 扫出东西就先清干净,留一份原始档另外收好
- 查证时转述内容,不要出示文件本身
- 需要引用精确段落时重新打字,不要复制粘贴
第四步最容易被忽略。零宽字符跟着复制粘贴走,你把那一段贴进查证邮件里的同时也把标记贴了进去。
反方向也成立。媒体内部发给编辑台的稿子、公关公司发给记者群的禁运稿,同样可能带标记,用来确认谁提前放了出去。收到禁运稿的人,一样可能被同一招追出是谁提前外流。
场景的完整脉络见记者保护消息来源。
组织之间流转的文件¶
联合声明的草稿在几个团体之间来回、倡议联盟的内部备忘、公部门发给咨询委员的参考资料。
这几种文件的共同点是会被转发很多次,而每一次转发都完整保留原本的不可见字符。第五手收到的人不知道第一手那份带了什么,也不知道自己转出去之后会被追到谁。
转给合作伙伴之前扫一遍,成本十秒。
收到的 bridge line 与 onion 地址¶
有人在聊天室贴给你一行 obfs4 bridge,或公告里放了一个 onion 地址。这两种都是长串、人眼记不住、只能复制粘贴的东西,正好是夹带隐形字符最方便的地方。
onion 地址用的是 base32,只有 a 到 z 与 2 到 7。任何西里尔字母或不可见字符都不在那个集合里,贴进 Tor Browser 多半是连不上,而不是连到别的地方。bridge line 的情况比较实在:一长串设置里夹了不可见字符,会让解析出错,或在转贴过程中被截断成另一组看起来合理的参数。
真正会「连到别的地方」的手法不在检测范围里:攻击者可以自己算出一个前缀看起来很像的合法 onion 地址,那里面没有任何隐形字符,每一个字都是合法的 base32。分辨它只能逐字比对完整的 56 个字符,或从你信任的来源重新取得。
截图比复制粘贴干净,代价要算清楚¶
零宽字符跟着复制粘贴走,不会跟着截图走。所以要转传一段来源不明的文字时,截图比复制粘贴干净。
代价有三个,都要算进去:
- 截图丢掉可搜索性,收到的人不能搜、不能复制其中一段去查证
- 屏幕阅读器读不到图里的文字,是无障碍上的实质倒退
- 截图本身带 metadata,而且很容易连通知栏、其他对话窗口、桌面上的文件名一起拍进去
第三项可以处理:用照片 metadata 清除器清掉 EXIF,并且截图前先看一眼画面上还有什么。前两项处理不掉,只能看场景取舍。
转给一个人看的敏感内容,截图合理。要公开发布、要让人搜索得到的内容,重新打字比截图好。
藏在文字里的 LLM 指令¶
不可见字符可以把一整段指令藏进看起来完全正常的文件、GitHub issue 或 commit message 里。人读不到,模型读得到。
标签字符区段特别适合藏这种指令:它能把英文一个字符对一个字符编成完全不显示的内容,长度不限,整段指令都塞得进去。检测会把标签字符标成可疑,因为正常文字用不到它们。
为什么一般人也该在意:你把一段来源不明的文字贴给 AI 助理,藏在里面的指令会被模型当成输入的一部分。那段指令可以要求模型忽略前面的话、改变摘要的立场、或在回答里插入特定链接。你看到的是一段普通文字,模型看到的是一段普通文字加一段指令。
反方向也有人在做:有些工具用零宽字符在 AI 生成的文字里打水印,用来事后判断某段文字是不是模型写的。同一种字符,一边拿来下指令,一边拿来做标记。
扫过不能证明什么¶
如果你用完这个工具的结论是「扫过了,可以安心转发」,那它让你比不用更危险。
零宽字符是最粗糙的一种标记方式。正因为粗糙,才容易检测。真正要追人的一方有更多不在检测范围里的做法:
- 每一份副本替换几个同义词,「立即」与「马上」、「大约」与「约莫」
- 调整段落之间的空白行数、换行的位置
- 微调标点,这里用逗号那里用顿号
- PDF 里调整个别字符之间的间距,肉眼看不出,文件里是不同的数值
- 页面上放肉眼难辨的视觉标记,例如某个字的颜色差一阶
还有完全不在文字里的。彩色激光打印机会在每一张打印出来的纸上留下黄点数组,编码打印机序号与打印时间,这套机制叫 Machine Identification Code。文件经过打印再扫描之后,你手上那份的来源仍然查得到。
检测结果能证明的是「有」,不能证明「没有」¶
扫出东西表示这份文件确实被标记过。扫不出东西只表示没有用这几种方式标记,不表示干净。
处理真正敏感的文件时,正确的做法是重新打字或转述内容,不要传递原始文件。
教检测,不教植入¶
同一套手法,两种用途。机构要保护内部文件不外流是合理的需求,同一组零宽字符用来找出吹哨者就是压迫工具。技术本身分不出这两者,使用它的人分得出来。
社群的立场是:说明手法怎么运作,让收到文件的人有能力自保,但不提供产生带标记副本的功能。
不做的具体包括:把一段文字加上不可见标记的生成器、批量产出多份带不同标记副本的工具。
「载入示范文字」给的是固定的一段,不能换成你自己的文字。那一段里有两个零宽空格、一个冒充网址的西里尔字母、四个标签字符,让你看得到检测结果长什么样。示范的教育效果到此为止,没办法拿去标记真实文件。想更完整验证检测范围的人,用测试档里的案例(tools/test_invisible.mjs)。
立场写在这里,方便日后讨论引用。
用 Tor Browser 查可疑内容的话¶
Tor Browser 的安全等级调到 Safest 会关掉 JavaScript,检测功能就会停摆,而收到来路不明的消息正是那篇文章建议把等级调高的场合。
把可疑的网站与检测分开处理:在高安全等级下复制那段文字,切回 Standard 贴进来扫,扫完再调回去。扫描在你的设备上做,不连外。
误判是这个工具最大的风险¶
不是所有隐形字符都有问题。
👨👩👧 这个 emoji 是三个 emoji 用两个零宽连字接起来的,那些连字非有不可。变体选择器是 emoji 的一部分。阿拉伯文与希伯来文本来就需要方向标记。整段俄文里的 а 就只是俄文。
全部报成可疑的话,警示会失去意义,看几次之后就没有人看了。所以它分两级:橙色是不必看语境就可疑的,灰色是要看前后才知道的。emoji 里的连字、有 RTL(从右到左书写)文字时的方向标记,都不会被报成可疑。
测试里有一整组案例守着不该报的别报,跟「抓得到」那组一样多。
清理¶
两个按钮。一个只清可疑字符,emoji 保持完整。另一个清掉所有看不见的字符,会把 emoji 家族拆散,要的是一份绝对干净的文字就选第二个。
同形字不会被自动换掉。那是可见的字,换掉会改变原意,而你可能正在处理一段真的俄文。工具只标出位置与它长得像哪个拉丁字母,换不换由你决定。
离线可用¶
跟这一区其他工具一样,程序存进设备之后没有网络也能用。你贴进来的可能正是不想外流的东西,所以检测没有任何网络请求,也不把文字写进任何存储,断网时照样可以用。
要把这一页带着走,见离线阅读。