跳到主要内容
不用登录就能换到的 token,和压在垫子下面的钥匙

不用登录就能换到的 token,和压在垫子下面的钥匙

阿舟
阿舟

· 阅读约 7 分钟

十月二十三号那篇 CyberInsider 的报道出来时,我正在改一个鉴权中间件。Alex Lekander 写的。读到中间那句“无需登录即可取得一个访问令牌”,我把编辑器里的改动撤了,重新把那段读了一遍。

不用登录。

这四个字比“三十万台”更让我坐不住。大数字看多了会麻,三十万和十七万对我来说没差。不用登录不一样——这是一扇没装门的门。等等,这话后面我要收回,先这么放着。

Flock Safety 那套自动车牌识别,同行不用我铺:车过去就记,不管你有没有嫌疑,记完能按车牌、位置、时间戳检索,车牌糊了拿车型特征兜底。警方和私人客户都在用。这套东西该不该存在,不是我这篇要聊的。我要聊的是它的接口。

具体哪种实现漏的,公开材料里没写,我也不猜人家的代码。但“不用登录换 token”这条路来来回回就那么几种:/token 之类端点自己不鉴权,谁调都给;密钥塞进客户端,反编译一下就在那儿躺着;或者某个内部接口忘了挂进网关的鉴权链。三种我都在真实项目里见过。第三种最常见,也最蠢——不是不会写鉴权,是把鉴权外包给了一层看不见的东西。

我自己踩过这个。一个内部服务,鉴权全交给网关,服务本身一行 auth 代码没有。逻辑上说得通,所有流量都过网关。直到某次发布把一条路由规则覆盖掉了。

画外音:那条规则现在还在我备忘录里躺着,标题叫“别再这么干”。

后来改成双保险,丑,但有效:

@app.route("/device/location")
def location(device_id):
    if not verify_token(request.headers.get("Authorization")):
        return unauthorized()      # 网关拦过一遍,这里再拦一遍
    ...

这不是 paranoid,是承认“我总有一天会把网关配错”。承认这一点,成本是三行代码;不承认,成本是三十万台设备的位置。

还有一个更隐蔽的版本,AI 特别爱写。它给你生成一个 handler,从 header 里读 X-User-Id,拿这个值去查数据。干净利落,注释还写得挺客气。

user_id = request.headers.get("X-User-Id")   # 这行“看起来对”

看起来对,因为它确实假设了网关会注入这个头、并且把外部传进来的同名头剥掉。假设本身没错。错在这个假设没写在任何地方,也没人测。哪天服务被直接暴露出去——内网扫描、调试端口开错、或者只是有人把网关规则改了——这个头就是用户可以自己填的。一个“看起来对”的鉴权比没有鉴权更危险,因为它会让人放心。

回到清单。Proton 公开的那张地图,用的是 Joshua Michael 从 Flock 自己系统里拿到的清单——超过 17 万台摄像头,13 万多台其他设备。来源很关键:它不是 DeFlock 那种志愿者拿眼睛看、拿手机报的众包数据,是公司记录。众包是“我猜这儿有一个”,这是“它自己说的”。

Proton 是瑞士那家做 Proton Mail 和 Proton VPN 的公司,它把地图托管下来了,让项目能继续公开访问——因为 Michael 正面临法律威胁和恐吓。一个卖加密邮箱的公司替一个安全研究员挡了一下。我不觉得这是什么纯粹的好心,它卖的就是这个。但这不重要,重要的是地图还在。

时间线捋一下,不然容易看晕。2025 年 11 月 Michael 发现那个令牌,12 月把设备清单存档。2026 年 9 月 23 日,论文和地图发布。9 月 25 日那份更新里,停止函、诉讼威胁、通知客户已通知执法部门,三样一起上桌。

然后是我最想说的这一段。Flock 在通知里讲,他们调查了暴露的令牌、关掉了访问路径,起初没发现未经授权访问的证据。9 月再查,说发现了与该令牌有关的异常活动,但取证审查没发现客户数据受到影响。

我读第一遍的反应不是“还好没泄露”,是:那 2025 年 11 月到 2026 年 9 月,这十个月在干嘛?

Michael 的说法比我狠,也比我准——最初的结论说明他们发现未授权访问的能力本身就有问题。这不是骂人,是技术判断。一个系统如果拿不出“谁在什么时候、用哪个令牌、查了哪些设备”的记录,那“未发现异常”这五个字的信息量就是零。它不是结论,它是“我们看不见”的体面说法。

这不是什么高深的取证要求。你半夜让实习生跑了个脚本,第二天问它干了啥,它说“应该没动什么”——你会打开日志看一眼,对吧?如果连日志都没有,你信它还是信自己?

这块我太熟了。我审 AI 写的代码,最烦的就是这种:功能跑通,测试全绿,日志一行没有。出了事你连“它到底干了什么”都答不上来。Agent 半夜跑个脚本把表清了,你唯一的信息来源是 binlog 和你自己那点模糊的记忆。

所以我现在给 agent 派活有一条硬规矩:任何写操作,先 dry-run 出日志,日志落盘,再执行。

# 不是花架子,这个格式救过我
[2026-03-14T02:11:07Z] dry-run job=migrate_users rows=18234 target=staging

不是洁癖。是我需要一个能回答“发生了什么”的东西。Flock 这个案子把这个需求放大到三十万台设备的尺度上,又给我看了一遍。区别只是我丢的是一张测试表,他们丢的是“我们到底被查了多少次”这个答案。

扯远了,回正题。

然后是我这篇真正想让人不舒服的地方。404 Media 报道,加州奥兰治县情报评估中心 7 月散了一份公告,提醒警员注意那些到市议会开会、反对这套监控技术的人。公告自己承认没发现具体可信的威胁,但仍然要求警员留意“异常提问”和“徘徊”这类可疑行为,还把媒体到场、直播、情绪化交流列成潜在的公共安全关注点。

把提问列成可疑行为。

我不打算用“令人不安”来评这句话,那词太软。这是一份由情报部门发出的、自己承认不存在具体威胁、却依然要求盯着你的文件。它的功能不是安全规划。它的功能是让去开会的人在门口多犹豫三秒。三秒就够了。中心后来的回应说公告是为了支持安全规划,也承认言论和集会受宪法保护——这两句可以同时为真,也可以同时什么都不是。

写到这儿我回头看了眼开头。我说“这是一扇没装门的门”,这话顺了点,不太准。真实情况更可能是:门装了,锁也装了,但有一把钥匙被压在门口垫子下面,压了很久没人发现。区别在于,“没装门”是能力问题,“钥匙压垫子下”是流程问题——而流程问题更难改,因为它不出错的时候,一切看起来都正常。

Proton 那边有句提醒得转达:这张地图是 2025 年 12 月的快照,之后新增的、拆掉的设备都不显示。别拿它当“我家楼底下有没有摄像头”的查询工具用死。它是一份历史清单,不是实时路况。

它的用处也在这儿——它让你能去问对四个问题:这些设备在哪儿、车辆记录留多久、哪些机构能查、查询怎么审计。前三个 Flock 大概答得上来。第四个,就是上面那十个月。

两条我现在还在守的规矩:任何对外接口,鉴权写在自己身上,别全托给上游;任何能改数据、能拉位置的调用,先落日志再动手。都是返工换的,不是从哪篇最佳实践里抄的。

至于一家公司收到漏洞报告之后,第一件事是发停止函、威胁诉讼、通知客户已通知执法部门——这个反应本身,就是一次审计结论。

阿舟
阿舟

写代码写到一半开始怀疑人生,靠 AI 工具续命,顺手把踩过的坑都记下来。

查看主页 →