系統維護把一條閱後即焚連結貼進 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 /tw/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、LINE、微信差在哪

Slack 的路徑最好核對。官方 robots 給出了 User-Agent,你可以用同一串去要閱讀頁,看回傳的是不是靜態 HTML,以及隨後閱讀次數有沒有變。Slack 還寫了大約 30 分鐘的全域快取:同一條 URL 短時間裡被多人貼進不同頻道,不一定每次都重新打到你的來源站。卡片上出現站點標題,只說明中繼標籤或 <title> 被讀到了;閱讀頁預設標題是「閱後即焚」,裡面沒有測試句原文。

台灣日常交接更多走 LINE。LINE 沒有像 Slack 那樣公開的 robots 頁,不能把內部爬蟲的能力寫成官方條款。能當場看見的是:貼出網址後,聊天裡會不會出現標題卡片;接收方點開後,閱讀頁是解密、不完整,還是已焚毀。即時訊息產生卡片,常見做法仍是伺服器端抓取 HTML 的標題和摘要,而不是在接收方手機裡先跑完閱讀頁腳本。沒有公開文件時,以你這條測試連結的結果為準,不要把「出現了卡片」直接等同於「密文已被取走」。

微信同樣沒有公開 robots 頁。對岸同事或跨境專案仍常用它傳連結,核對方法和 LINE 一樣:看卡片有沒有測試句原文,再用完整連結確認次數還在不在。不要把簡體教學裡的「檔案傳輸助手」生搬過來當唯一試驗場——在台灣,用自己的 LINE Keep、測試群組或 Slack 私人頻道更方便重做。

企業信箱是第四條路。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 頻道、LINE 群組、微信聊天或信件執行緒裡,和把密碼明文貼進去相比,只是多了一層「點開才解密」。誰能搜到那條訊息,誰就能在焚毀之前開啟。關掉無痕視窗也帶不走已經存進書籤或下載資料夾的完整網址,見關掉無痕視窗之後下載、書籤和剪貼簿裡的密碼還在。

對照表:預覽之後還剩什麼

同一條測試連結、閱讀次數設為 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/tw/s.html?id=…"。回傳應是閱讀頁 HTML,標題或正文裡不應出現測試句。這一步只證明「只取文件時拿不到明文」,還不能代替真實聊天。
  3. 用瀏覽器開啟同一段「只有 id、沒有金鑰」的位址。應看到連結不完整,而不是原文。開啟開發人員工具 Network,勾選「保留紀錄」:應有狀態查詢,不應出現隨後那次取密文的成功回應。
  4. 立刻用完整連結(帶 #)在另一個分頁開啟。應解密出測試句。若上一步已經燒掉,說明實作或中間裝置把「無金鑰存取」也當成了閱讀——停在這裡,不要發真實內容。
  5. 另建一條同樣次數為 1 的測試連結,完整貼進你能控制的 Slack 頻道、LINE Keep、測試群組或微信。等預覽卡片出現(或確認沒有卡片)。不要點開閱讀頁。
  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 被抓過。用完整連結再開啟一次:仍能解密,說明次數還在;已焚毀,再另建一條,不要反覆重新整理同一條碰運氣。

LINE 或微信沒有公開 robots 頁,該信哪一句?

信你這條測試連結的結果。出現標題卡片,只說明有程式讀過頁面標題或摘要。接收方點開前,你自己先用完整連結開啟:仍是原文,說明這條通道上的預覽沒有取密文;已焚毀,就改走拆分或換一對一傳送。

把閱讀次數調到 2 或 3,能不能對抗預覽?

只能多留幾次「取密文」的額度,不能讓預覽變成安全方法。掃描器若每次都帶著金鑰執行腳本,次數仍會被用光。先用次數為 1 的測試連結看預覽屬不屬於前兩類;必須發進不穩定通道時,再考慮加次數,並接受「可能被多一個人開啟」。

建立和閱讀要註冊嗎?預覽機器人算不算「閱讀方」?

不需要註冊。建立與閱讀都對訪客公開。預覽機器人如果只取 HTML,不是一次閱讀;如果它發出了取密文的 GET,伺服器無法區分它和真人,次數照樣減。閱讀頁對接收方公開,沒有登入門禁,也沒有客服信箱可以找回已焚毀的內容。