运维把一条阅后即焚链接贴进 Slack 频道,卡片先弹出来,标题写着站点名。十分钟后接收方点开,页面却变成「已被焚毁」。两边都觉得自己没读过明文。真正先到达服务器的,往往不是同事的手指,而是聊天软件为了画预览发出的那一次 GET。

上一篇写过一次性把口令发给同事时为什么要把密钥放在 # 后面:那是「托管密文的 HTTP 服务看不看得到密钥」。本文换问题:人还没点,预览会不会先用掉一次阅读。密钥仍在 # 后面;创建与阅读都不用注册。MyPassGen 的阅后即焚打开即用,阅读次数默认 1、上限 10。下面不讲按钮怎么点,只对照你能在 Network、地址栏和聊天窗口里看见的东西。

先分清两件事

预览会不会烧掉密文,和聊天记录会不会留下完整网址,不是同一件事。只抓 HTML、不跑页面脚本的预览,通常拿不到 # 后面的密钥,也调不到取密文的接口。群记录里那一整段 s.html?id=…#… 却还在,谁复制谁就能打开。预览没烧掉,不等于链接已经不是凭证。

对方说已焚毁,你没点过

一次性链接的常见设计是:第一次取走密文,服务端就把密文清掉。默认阅读次数是 1 时,这一下用完就再没有第二份。发送方看到的成功创建、接收方看到的焚毁态,中间可以插进许多「不是人点的」访问:频道预览、邮件安全扫描、公司网关改写后再探测。

Slack 把这件事写进了产品文档。Unfurling links in messages 写:用户在消息里贴出链接时,Slack 会抓取该页并附上预览。官方 robots 页把执行这条抓取的机器人叫 Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots),并写明:它尽量少取页面(使用 HTTP Range),目的是抽出 oEmbed、Twitter Card 和 Open Graph 这类元标签;若标签指向图片或音视频,再另取文件做校验。Slack Robots 还写:同一 URL 的响应会在服务内缓存大约 30 分钟;他们不按 robots.txt 把自己挡在门外,因为这是代用户去取摘要,不是搜索引擎那种整站爬行。

所以「频道里已经出现卡片」只能证明:有一台不属于接收方的机器,对你贴出的网址发过至少一次 HTTP 请求。它不能证明明文已经被读走,也不能证明密文已经被计数。要判断烧掉没有,得看那一次请求打到了哪一层。

预览发出去的是哪一段网址

你复制的完整链接形态是 …/s.html?id={id}#{key}。问号后面的 id 会进入 HTTP 请求行;井号后面的密钥按协议留在客户端。依据见 RFC 3986 §3.5 与 RFC 9110 §7.1:目标 URI 排除 fragment,因为这一段留给客户端处理。预览机器人走的是普通 HTTP GET,请求行里合法的应是 GET /cn/s.html?id=…,后面那截密钥到不了托管密文的机器。

这也是「只抓 HTML 的预览」通常解不开明文的原因。阅读页要解密,必须先由浏览器脚本读取 location.hash,再向服务器索取密文,最后在本机用 AES-256-GCM 解开。预览爬虫没有井号后的密钥,手里只有编号。即便它把 s.html 的 HTML 全文存下来,里面也没有口令原文——阅读页是 noindex 的落地页,初始 HTML 里只有通用标题,明文要等脚本跑完才写进页面。

聊天软件保存的却是另一份东西。用户粘贴的是整段字符串,包括 # 和密钥。频道搜索、消息同步、以后换手机再打开同一条记录,拿到的仍是完整凭证。密钥放在井号后,解决的是「预览 GET 和服务端日志少看到密钥」;它保护不了「群记录里有没有完整链接」。更敏感的交接可以把编号和密钥拆到两条通道,见后文。

三种抓取,只有一种会计数

RFC 9110 把 GET 定义为安全方法:发出去不该有破坏性副作用。只为了画卡片而去 GET 一张网页,按语义不该把密文删掉。现实里的一次性工具如果把「第一次 GET 文档」就当成阅读,预览机器人就会先于接收方烧掉内容。差别不在聊天软件的名字,而在计数绑在哪一次请求上。

可以先按执行能力分成三类。第一类只取首屏 HTML,解析 <title> 和 Open Graph,不运行页面脚本。Slack 官方对 Link Expanding 的描述属于这一类:抽取元标签,必要时再取标签里写明的媒体文件。Apple 在 Ensuring Beautiful Rich Links 里写过:生成富链接时不运行 JavaScript,Open Graph 必须写在页面源码里。Discord 频道里的嵌入预览,常见实现同样是由 Discordbot/2.0 读取初始 HTML,而不是打开一个完整浏览器内核。

第二类会执行页面脚本,但请求里仍然没有 fragment。无头浏览器、部分企业扫描沙箱属于这一档。它们能跑阅读页的 JavaScript,却读不到 location.hash。对本站来说,没有密钥就不会去取密文,页面应停在「链接不完整」,阅读次数不应增加。

第三类会执行脚本,并且把完整网址(含 #)装进一个真正的页面环境。少数在本机用 WebView 打开「即将点击的链接」的安全软件,或发送方设备上会完整加载页面的预览实现,才可能走到「取密文并计数」。这一类不能靠协议保证,只能用测试链接在同一条通道上复现。

Slack、微信、邮件网关差在哪

Slack 的路径最容易核对。官方 robots 给出了 User-Agent,你可以用同一串去要阅读页,看返回的是不是静态 HTML,以及随后阅读次数有没有变。Slack 还写了大约 30 分钟的全局缓存:同一条 URL 短时间里被多人贴进不同频道,不一定每次都重新打到你的源站。卡片上出现站点标题,只说明元标签或 <title> 被读到了;阅读页默认标题是「阅后即焚」,里面没有测试句原文。

微信没有像 Slack 那样公开的 robots 页,不能把内部爬虫的能力写成官方条款。能当场看见的是:贴出网址后,聊天里会不会出现标题卡片;接收方点开后,阅读页是解密、不完整,还是已焚毁。国内即时消息生成卡片,常见做法仍是服务端抓取 HTML 的标题和摘要,而不是在接收方手机里先跑完阅读页脚本。没有公开文档时,以你这条测试链接的结果为准,不要把「出现了卡片」直接等同于「密文已被取走」。

企业邮箱是第三条路。Microsoft 在 Safe Links 说明里写:入站邮件会做 URL 扫描和改写,点击时再验证;改写后的地址带 safelinks.protection.outlook.com 这类前缀。投递时扫描和点击时跳转,都可能对目标再发 GET。你要核对的是两处:邮件正文里看到的是否已被包一层;点开之后地址栏是否还带着 # 后面那一截。密钥若在改写或跳转中丢失,阅读页应提示链接不完整,而不是解出原文。密钥若被完整带进一个会执行脚本的沙箱,才可能计数。不要假设所有网关都「只看 HTML」。Microsoft Teams 频道里的链接同样可能走 Safe Links,策略因租户而异。

本站阅读页实际打了哪些请求

MyPassGen 的阅读页打开后,脚本按顺序做两件事。先用编号查询状态:这条请求只回答还在、已焚毁还是已过期,不增加阅读次数。没有 # 后面的密钥时,到此为止,页面提示链接不完整。有密钥时,再发出取密文的 GET;这一次才把 read_count 加一。次数达到你设定的上限(默认 1,最大 10)后,服务端清掉密文,再开就是焚毁态。过期则按创建时选的 TTL:1 小时、24 小时、7 天,或只按次数、不设 TTL。

因此,只 GET s.html?id=… 的预览,和只打状态接口的扫描,都不会用掉那一次阅读。会用掉次数的,是「带着密钥的阅读页脚本」发出的取密文请求。创建时浏览器在本机用 AES-256-GCM 加密,IV 12 字节,明文上限 32 KB,服务端只暂存密文;密钥不进 HTTP 请求行。算法与「明文有没有上传」,核对方法见浏览器里做加密,怎么当场核对明文没有上传。

阅读页没有单独的「揭示」按钮:密钥齐全时,打开标签页就会取密文。这和「预览爬虫只取 HTML」并不矛盾——爬虫通常到不了取密文那一步。矛盾出现在第三类抓取:完整网址被装进会执行脚本的环境。这时它和真人点开没有区别,默认 1 次的链接会被用掉。你不能从卡片样式判断属于哪一类,只能用下一节的步骤看状态。

预览没烧掉,群记录仍是凭证

完整链接留在 Slack 频道、微信聊天或邮件线程里,和把口令明文贴进去相比,只是多了一层「点开才解密」。谁能搜到那条消息,谁就能在焚毁之前打开。关掉无痕窗口也带不走已经存进书签或下载文件夹的完整网址,见关掉无痕窗口之后下载、书签和剪贴板里的口令还在。

对照表:预览之后还剩什么

同一条测试链接、阅读次数设为 1,预览发生之后,发送方和接收方各自能看见的东西并不一样。下面按「你能打开的页面」来写,不按产品口号。

发生了什么 聊天窗口里常见现象 完整链接再打开应看到
只取 HTML 元标签,不跑脚本 出现标题卡片,没有测试句原文 仍可解密出测试句
跑了脚本,但请求没有 # 卡片或空白预览;服务端只有状态查询 仍可解密;无密钥的那次应提示不完整
完整网址被装进会执行脚本的环境 卡片或扫描报告;阅读次数已用掉 已焚毁或已过期,没有原文
邮件网关改写了 URL,跳转后丢掉 fragment 正文里是 safelinks… 一类包装地址 链接不完整,密文通常还在

第四行和第三行不要混。密钥丢了,接收方打不开,发送方却还能用原始完整链接打开——说明次数没被用掉,只是对方拿到的那一截不完整。密钥还在、页面已焚毁,才是预览或扫描抢先读了。前者补发井号后的那一段即可;后者必须重新创建,没有服务端明文备份,也没有客服邮箱可以找回。

当场核对

下面这组步骤不依赖任何品牌承诺。全程使用不会登录真实账户的测试句,例如 orange-lake-7。不要拿正在使用的主密码、生产密钥或真实焚链练手。

  1. 打开阅后即焚,写入测试句,过期选 24 小时,阅读次数保持 1,生成链接。记下完整地址,确认形态是 s.html?id=…#…。打开即用,无需注册。
  2. 把井号前面的部分单独复制出来。在终端对这一段发一次带 Slack User-Agent 的请求,例如 curl -A "Slackbot-LinkExpanding 1.0 (+https://api.slack.com/robots)" "https://mypassgen.com/cn/s.html?id=…"。返回应是阅读页 HTML,标题或正文里不应出现测试句。这一步只证明「只取文档时拿不到明文」,还不能代替真实聊天。
  3. 用浏览器打开同一段「只有 id、没有密钥」的地址。应看到链接不完整,而不是原文。打开开发者工具 Network,勾选「保留日志」:应有状态查询,不应出现随后那次取密文的成功响应。
  4. 立刻用完整链接(带 #)在另一个标签打开。应解密出测试句。若上一步已经烧掉,说明实现或中间设备把「无密钥访问」也当成了阅读——停在这里,不要发真实内容。
  5. 另建一条同样次数为 1 的测试链接,完整贴进你能控制的 Slack 频道、微信文件传输助手或测试群。等预览卡片出现(或确认没有卡片)。不要点开阅读页。
  6. 预览出现后,在电脑浏览器打开同一条完整链接。仍能解密,说明这条通道上的预览属于前两类。已经焚毁,说明中间有第三类抓取,或你自己的某个设备预取了带密钥的页面。需要再传时重新创建。读完后按复制密码之后剪贴板还会被谁读走覆盖剪贴板;不要把带 # 的地址存进书签。

企业邮箱再加半步:把测试链接发给自己的工作邮箱,看正文是否被包成 Safe Links 一类地址,再看点击后地址栏是否仍有密钥。丢了密钥就改用「编号走邮件、密钥走电话」;被烧掉就提高次数或换通道。MyPassGen 不会代你判断某家网关属于哪一类,核对结果以你刚才那几扇窗口为准。

必须发进会预览的群时怎么拆

默认 1 次适合「对面拿着完整链接、立刻打开、然后作废」。频道、大群、会生成卡片的邮件列表,先用测试链接走完上一节。确认预览不计数之后,再发真实内容。若测试已经被烧掉,不要指望调高次数能让预览「变安全」:次数变成 2,只是允许再有一次真人打开,扫描器若每次都执行脚本,仍可能把次数用光。

更稳的拆法是两条通道。一条消息只发 s.html?id=…,预览最多拿到编号和通用标题。另一条——电话、当面、或另一个即时消息账号——只发 # 后面那一截。没有两半就解不开。这是用法,不是产品默认拆分;创建页生成的仍是一条完整链接,方便一对一交接。

口令本身应在本机生成,不要先写进群再删。MyPassGen 的密码生成器随机模式 6–128 位,默认 16,低于 8 位会提示较弱;打开即用,生成结果不作为业务数据上传。超过 32 KB 的证书包或导出表,不要硬塞进焚链,走文件加密盒:浏览器里 AES-256-GCM 流式加密,单文件不超过 5 GB,输出 .lock / .enc,口令另发。网盘只负责存密文,见把文件丢进网盘前谁拿得到明文。

做完「预览之后完整链接是否仍可解密」和「群记录里是否留下完整凭证」这两次核对,你就已经能回答本文的问题:只取 HTML 的预览通常不会先烧掉本站的阅后即焚;会执行脚本并带上 # 的抓取会。卡片本身给不了答案,状态页和第二次打开才给。

常见问题

Slack 频道里已经出现预览卡片,链接是不是废了?

不一定。Slack 官方写明 Link Expanding 抽取的是元标签,并且用 Range 尽量少取页面。卡片只能证明阅读页 HTML 被抓过。用完整链接再打开一次:仍能解密,说明次数还在;已焚毁,再另建一条,不要反复刷新同一条碰运气。

微信没有公开 robots 页,该信哪一句?

信你这条测试链接的结果。出现标题卡片,只说明有程序读过页面标题或摘要。接收方点开前,你自己先用完整链接打开:仍是原文,说明这条通道上的预览没有取密文;已焚毁,就改走拆分或换一对一发送。

把阅读次数调到 2 或 3,能不能对抗预览?

只能多留几次「取密文」的额度,不能让预览变成安全方法。扫描器若每次都带着密钥执行脚本,次数仍会被用光。先用次数为 1 的测试链接看预览属不属于前两类;必须发进不稳定通道时,再考虑加次数,并接受「可能被多一个人打开」。

创建和阅读要注册吗?预览机器人算不算「阅读方」?

不需要注册。创建与阅读都对访客公开。预览机器人如果只取 HTML,不是一次阅读;如果它发出了取密文的 GET,服务端无法区分它和真人,次数照样减。阅读页对接收方公开,没有登录门禁,也没有客服邮箱可以找回已焚毁的内容。