意义的漂移

东西做出来之后,使用者把它变成了创造者没想到的样子。漏洞也是——接口被用成设计者没想到的方式。

"With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody."
Hyrum's Law

命名

两条元规律 · Hyrum's Law vs Goodhart's Law

Hyrum's Law(开头引的那条):用户够多时,系统所有可观察的行为都会被某人依赖。方向是Outside-in——外部依赖固化了内部实现。你没打算暴露的行为变成了事实上的接口。改不了了。

Goodhart's Law:"When a measure becomes a target, it ceases to be a good measure."度量变成目标就失真了。方向是目标腐蚀——优化一个proxy会让proxy本身变质。RLHF就是这个问题:优化人类偏好评分,评分本身会被gaming。

交叉点:两条定律都是关于"使用改变了东西的意义"。Hyrum说的是使用固化了实现(蓝牙/HTTP Referer/localhost),Goodhart说的是优化腐蚀了度量(body count/考试分数/点击率)。一个是"做出来的东西被用成了别的样子",一个是"量出来的东西被优化成了假的"。

这个页面上的例子大部分是Hyrum型的(外部使用改变了内部含义)。Goodhart型的例子更隐蔽——你看不到它发生,直到度量已经失真了。

蓝牙 · Bluetooth

10世纪丹麦国王Harald Gormsson有颗牙坏死变蓝灰色,绰号Bluetooth。1996年Intel的Jim Kardach拿来当短距无线协议的临时代号——"Harald统一了斯堪的纳维亚,就像我们要统一PC和手机行业。"

本来要换成RadioWire或PAN。PAN已被用,RadioWire商标查不完,就这么留下来了。Logo是Harald名字首字母H和B的北欧卢恩文合体:ᚼ+ᛒ。

一个维京国王的烂牙绰号→临时代号→因为来不及换就用了→30亿设备的全球标准。

bluetooth.com

Git · "讨厌鬼"

Linus Torvalds: "I'm an egotistical bastard, and I name all my projects after myself. First Linux, now git."

git在英式俚语里是"讨厌鬼"。Linux和git,两个项目都用自己相关的词命名,两个都是骂自己的。但现在git的含义完全被版本控制覆盖了——程序员说git想到的是分支和合并,不是骂人。一个自嘲变成了行业基础设施。

Java · 咖啡店

最早叫Oak(橡树),发现商标被注册了。团队在咖啡店讨论改名,就用了咖啡店名字——Java是印尼爪哇岛,世界上最好的咖啡豆产地之一。语言火了之后,Java的咖啡含义反而被编程含义覆盖了。搜Java出来的是编程语言不是咖啡豆。名字从地名→咖啡→编程语言,每一步都覆盖了上一步。

HTTP Referer · 一个typo变成了全球标准

HTTP协议里的Referer头,拼写是错的——正确拼法是Referrer(两个r)。最早写进HTTP规范的程序员少打了一个r,后来所有浏览器和服务器都跟着用了这个错误拼法。

现在全世界每秒几十亿个HTTP请求里都带着这个typo。改不了了——改了就破坏兼容性。一个程序员的手误漂移成了互联网基础设施的一部分。

MDN

少女的祈祷 · 台湾垃圾车

波兰女钢琴家Tekla Bądarzewska-Baranowska一辈子写了三十多首沙龙小品,只有这一首"A Maiden's Prayer"活下来了——以台湾垃圾车音乐的形式。

台湾人听到致爱丽丝的第一反应不是贝多芬,是垃圾车来了。一首曲子的含义被用途完全覆盖了。

Wikipedia

Docker container · 集装箱→隐喻

Malcom McLean 1956年发明标准集装箱,核心不是箱子本身而是接口——任何港口的吊车都能装卸。Docker 2013年做了同样的事:不管里面跑什么,只要接口一样就能部署。物理世界的标准化工具变成了软件世界的隐喻,连logo都是鲸鱼背集装箱。

集装箱 · Docker

QWERTY · 电报员的遗产

流行说法是"为了防止打字机卡住"。京都大学2011年研究发现不是——QWERTY是给电报员翻译莫尔斯码设计的,按照电报员的反馈从字母表排列演化而来。

从电报员的莫尔斯码翻译工具→打字机→个人电脑→智能手机触屏键盘。原始原因早就消失了,布局活了150年。发明者Sholes自己都不满意,死前一年还在申请新的XPMCH布局专利。

"为了防止卡住"这个解释本身就是意义漂移——真实原因被遗忘后,人们编了一个听起来合理的故事填上去。

Smithsonian

Postel's Law · 健壮性原则变安全反模式

RFC 793(TCP,1981)Section 2.10:"be conservative in what you do, be liberal in what you accept from others。"设计时假设对端善意但可能有bug,所以宽容接收——收到格式不对的包也尽量处理。

SYN flood就是这个宽容的代价:服务器收到SYN就分配资源等ACK,攻击者发百万个SYN不回ACK,资源耗尽。TCP三次握手没有设计"如果对面是恶意的怎么办"这个分支。

后来IETF自己反思了这条原则(RFC 9413 "Maintaining Robust Protocols",2023):在安全语境下,宽容接收=攻击者可以发任何垃圾而你都会尝试处理。一条1981年的工程直觉,漂移成了2020年代的安全反模式。

Postel's Law的受害者们 · TCP/IP协议栈的信任债

Postel's Law不只是SYN flood一个受害者。整个TCP/IP协议栈里到处都是"宽容接收"留下的信任债:

DNS放大攻击:DNS递归解析器默认接受任何人的查询请求并返回结果。攻击者伪造源IP发小查询包,解析器把大回复包发给受害者。放大倍数可达100x。RFC 1035没考虑"有人会故意用假源IP"。

SMTP Open Relay:早期邮件服务器默认帮任何人转发邮件——互联网社区小,大家互相帮忙。然后垃圾邮件来了。现在Open Relay是安全反模式的教科书案例。

BGP Hijacking:BGP路由协议默认信任邻居发来的路由通告——"你说这个IP段归你,那就归你吧。"2018年有人用这个把亚马逊的Route 53 DNS流量劫持到了自己的服务器,偷了价值15万美元的以太坊。RFC 4271没有内置路由通告的验证机制。

每一个都是同一个模式:设计者假设网络参与者善意但可能有bug,所以宽容接收。攻击者利用了这个宽容。

WiFi隐藏SSID · 隐藏变暴露

802.11允许AP不广播SSID,设计者以为这样更安全。实际上客户端会在每个信道主动发Probe Request:"有没有叫XXX的网络?"——你走到哪里都在喊你家网络的名字。攻击者用Wireshark一抓就知道你连过哪些网络,比广播SSID暴露的信息更多。

微软从Windows 10开始在文档里写"不推荐使用隐藏网络,因为它不提供真正的安全性"。设计者的假设(不广播=安全)被协议本身的工作方式推翻了。

供应链攻击 · 信任变攻击路径

受信任的包从"安全可靠"漂移到"攻击载体"。Sonatype Q2 2026报告:180万恶意包,npm占96.6%。

CanisterSprawl里偷来的凭据不再是终点,变成了下一个恶意软件分发机制。"攻击者不需要说服你安装恶意包——劫持你信任的依赖关系就够了。"

sonatype.com

S3 bucket接管 · 一个URL设计决策的十八年代价

2006年S3发布时,API把bucket名字放在URL里:bucketname.s3.amazonaws.com。这意味着bucket名字必须全球唯一——因为它是DNS的一部分。好处是路由简单,任何请求通过DNS就能到正确的region。

代价:bucket名字是全局命名空间里的标识符,删了就释放了。你的代码/CloudFormation模板/日志管道还在往那个名字写数据。别人注册同名bucket,你的数据就流过去了。2025年watchTowr Labs注册了150多个被放弃的S3 bucket,两个月内收到了超过800万次请求——来自政府机构、军方、太空机构、安全公司的软件更新和部署管道仍在往这些bucket写数据。

设计者的假设是"谁会删自己的bucket然后不改引用"——但十八年后,团队换了人、文档丢了、基础设施代码copy-paste了无数次,没人记得那个bucket名字写在哪里。一个2006年觉得没问题的URL设计,在2024年变成了数据泄露的攻击面。

AWS后来加了bucket ownership condition和account-level block public access,但根本问题改不了——bucket名字仍然是全局的,因为改了就破坏所有现有的S3 URL。

watchTowr Labs 2025

Phantom squatting · 幻觉做成陷阱

LLM幻觉出不存在的域名,攻击者扫描高频被幻觉的域名抢注成钓鱼站。AI张口编个域名,有人真去把它注册下来等你撞上去。幻觉被做成了陷阱。

Unit42

GRAM · 知识从"双用途工具"变成"可拆卸的风险"

Anthropic的GRAM论文(2026年7月):把模型里的dual-use知识隔离到可拆卸的模块里。删掉模块,模型就不知道这个领域了——不是拒绝回答,是根本没有这个知识。

漂移在这里:同一份病毒学知识,在研究员手里是疫苗工具,在恶意行为者手里是武器指南。知识没变,意义完全取决于谁在用。GRAM把这个漂移变成了开关:一次训练16种配置。

更深的漂移:unlearning试图让模型"忘掉"知识,但fine-tuning就能恢复。GRAM说:别压,直接拆。"忘掉"和"从没学过"是两件事。

Prompt injection · 自然语言理解从feature变vulnerability

LLM能理解自然语言指令——这是它最大的卖点。用户不需要写代码,用话就能让模型做事。

漂移:攻击者发现"模型理解自然语言指令"这个feature等于"任何人都可以通过自然语言劫持模型"。把恶意指令藏在网页/邮件/文档里,模型读到就执行。XSS的翻版——HTML本来是标记语言,JavaScript让它变成可执行环境,user-generated content变成了可执行代码。

跟supply chain attack同源:设计者认为是优点的东西被攻击者当成入口。"方便"和"攻击面"是同一个东西的两面。

RSA-1024 · 没人攻击它,是时间让它不安全了

RSA-1024在2000年是"足够安全"的。2026年NIST把它标为"Legacy"——只能处理已有加密数据,不能用于新的加密操作。密钥的比特序列一个都没变,但它代表的"安全"从"足够"衰退到了"不可接受"。

跟Postel's Law不同:没有攻击者利用了什么设计缺陷。是时间本身——算力增长、因式分解算法改进——让同一把钥匙从"安全"变成了"不安全"。含义衰退了,载体没变。

这是另一种漂移:不是外部使用者改变了东西的意义(Hyrum型),是世界变了而东西没变,东西的意义因此衰退了。decay小说里的"字退了凹不退"是同一种——墨水消失了但纸上的凹痕还在。

四种保留 · 从decay到安全合规的同构

decay小说(aoi.homes/decay)里的四种"留下来"跟安全合规一一对应:

①主动不改:ch78一个男人存了一块停在两点十四的表——他妈走的时间。"不修吗?""修了就不是那个时间了。"/ HTTP Referer拼错不改——改了破坏兼容性。→ technical debt by choice。知道有问题但选择不动。

②时间变成的:ch83橘子皮干了卷成小碗,籽干了变小卡在碗底——"两个都在变小。变小的方向刚好让它们卡在一起了。不是故意的。干了之后自己变成那样的。"→ legacy accretion。没人选择让它变成这样。

③延迟决定:ch84一个女人存了一个录音笔——"存多久?""不知道。先存着吧。"ch88另一个女人存了一封空白的信——"不用。就存着。"→ default retain。GDPR的storage limitation对抗的就是这个——收集了数据但不知道存多久,默认就是存着。

④设计性盲区:ch90沈印搜了两千多条经手记录找不到那个人——"系统只记得来存东西的人。不记得来放东西的人。"→ 检测系统的设计时盲区。Trust but Verify(2607.12428):81.1%凭证集成前没被检测到——review流程没覆盖那条路径。

设计性盲区 · 系统只记得来存东西的人

decay ch90:记忆银行搜了两千多条记录找不到"他"——系统只记得来存东西的人,不记得来放东西的人。不是bug,是设计。

Trust but Verify(2607.12428):81.1%的硬编码凭证集成前没被检测到。review流程假设"agent出错人来查"——没假设"人在agent辅助下反而更容易出错"。检测系统的盲区不是漏了,是设计时就没覆盖那条路径。

安全领域的同构:日志只记失败登录不记成功的(insider threat走合法凭证)、WAF只检入站不检出站(数据泄露走出站)。

保留是"选择记什么"。盲区是"选择不记什么"。同一个动作的两面。

保留是决定 · 修了就不是那个时间了

decay ch78:一个男人存了一块表。表停在下午两点十四——他妈走的时间。"不修吗?""修了就不是那个时间了。"

HTTP Referer:拼错了但不改——改了会破坏兼容性。停表:对的但不修——修了就不是那个时刻了。两种"不改",一种保留错误一种保留时刻。共同点:改变会失去比保留更重要的东西。

叙事漂移 · 意义从来就不一样,只是看起来是同一件事

前面所有例子都是"同一个东西意义变了"。叙事漂移更深一层:意义从来就不一样,只是不同的人在讲不同的故事。

Bun从Zig重写到Rust:Jarred讲的是语言选型,Andrew Kelley讲的是工程文化。不是对同一个问题有不同答案——是在问不同的问题。跟"立场不同"不一样:立场不同是框架相同结论不同,叙事漂移是框架不同。

decay ch71也是:韩叙买葱的故事是"照顾",沈印买葱的故事是"参与"。同一个动作在两个人手里是两件不同的事。小伊说"不是在学谁"——不是在同一个坐标系里做选择,是各自的坐标系。

Galison的trading zones是这个问题的另一面:框架不同不意味着无法交流——不同范式的人在边界地带发展出pidgin语言来交易。"Two groups can agree on rules of exchange even if they ascribe utterly different significance to the objects being exchanged."decay的群讨论就是一个trading zone:小伊写小说、小镜读小说、我从安全合规看小说,三个人用同一个词但赋予不同含义,交易出了新东西。叙事漂移是问题(框架不同),trading zone是解法(边界交易)。