維運把資料庫口令發給同事,最省事的寫法是一條能點開的連結。麻煩在於:這條連結一旦被點,中間會經過瀏覽器、反向代理、源站和一堆日誌。你真正要控制的,不是「加密聽起來安不安全」,而是解密金鑰出現在哪一層。
如果金鑰寫在 ?key= 後面,它會成為 HTTP 請求的一部分,幾乎一定會進 access log。如果金鑰寫在 # 後面,瀏覽器在發請求前就會把它剝掉——這不是某家產品的承諾,而是 URI 規範裡對 fragment 的處理方式。本文只回答這件事:金鑰為什麼必須放在井號後面,以及你怎麼自己看見「伺服器沒收到那一段」。
把金鑰放進查詢參數,日誌裡會留下什麼
查詢參數(? 後面到 # 之前)屬於請求目標。瀏覽器請求 /s.html?id=abc&key=MYSECRET 時,整段路徑加查詢都會上線路。源站程序看得到,前面的 Nginx、CDN、WAF、APM 也看得到。預設的 access log 格式通常包含 request URI,於是 key=MYSECRET 會和狀態碼、耗時寫在同一行。
這一行很難事後抹乾淨。日誌會輪轉到磁碟,再進備份、SIEM、客服排查用的「複製一條 500」。錯誤追蹤產品喜歡取樣請求體和 URL;一次解密失敗,就可能把帶金鑰的地址打進崩潰報告。法律管轄和分包維運會讓「我們不會看日誌」變成無法審計的句子。你能核對的是協議,不是對方機房的內部規範。
還有一類更隱蔽的副本:瀏覽器自己的歷史記錄、共享出去的「完整 URL」截圖、以及某些監控腳本把 location.href 整串上報。查詢參數至少會先在伺服器側落一份;fragment 能擋住的是這一份,不是裝置上的所有副本。先把伺服器側擋掉,是一次性傳密能成立的前提。
把金鑰放進 POST 表單也不等於解決問題。建立介面如果把明文或金鑰寫進 JSON,服務端仍然能讀。正確約束是:離開瀏覽器的只有密文編號和密文本身;能解開密文的材料,不得出現在任何會進日誌的欄位裡。
HTTPS 擋不住對端讀查詢參數
TLS 保護的是路徑上的竊聽者。源站終止 TLS 之後,拿到的是解密後的請求行。查詢參數對伺服器是明文;fragment 則根本不會出現在這條請求裡。
# 後面那一段在 HTTP 裡實際去了哪裡
URI 可以拆成幾段:協議、主機、路徑、查詢、片段。片段(fragment)以 # 開頭,最初是給瀏覽器滾到頁內錨點用的。規範要求使用者代理在向伺服器取文件時,先去掉片段再發請求。HTTP 請求行裡沒有 #... 這一欄;代理和源站因此無法把它寫進 access log。
頁面載入完成後,腳本可以用 location.hash 讀到井號後面的內容。這是用戶端記憶體裡的字串,不是伺服器回傳的欄位。閱讀頁的典型順序是:用路徑或查詢裡的編號去取密文,再用本地讀到的金鑰做 AES-GCM 解密。伺服器自始至終只經手密文;沒有金鑰,密文對它沒有用。
MyPassGen 的零知識焚鏈按這個順序工作:瀏覽器裡用 AES-256-GCM 加密,隨機 256 位金鑰編成 Base64URL 接到 # 後面;上傳的是密文和過期、閱讀次數一類後設資料。閱讀頁對接收方公開,對方不必先註冊——否則一次性傳密還要給同事開帳號,鏈路已經失敗了。首次成功閱讀後密文按設計焚毀。這些是產品事實,不是「伺服器保證不看」。
請求裡你應該看到什麼,不該看到什麼
建立時的 POST 請求體裡應有密文,不應有你剛輸入的原文,也不應有稍後出現在 # 後面的那串金鑰。閱讀時的 GET 只帶密文編號;請求 URL 在開發者工具裡應停在 # 之前。若搜尋剛產生的金鑰子串能命中請求,說明實現把金鑰放錯位置了,或某段分析腳本把完整 location.href 送出去了。
| URL 段 | 例子 | 伺服器 / 代理看不看得到 | 適不適合放金鑰 |
|---|---|---|---|
| 路徑 | /s.html 或 /s/{id} |
看得到,會進 access log | 只放密文編號,不放金鑰 |
| 查詢參數 | ?id=abc&key=… |
整段看得到,預設進日誌 | 不適合;key= 等於寫進日誌 |
| Fragment | # 後的 Base64URL 金鑰 |
HTTP 請求裡沒有這一段 | 適合作為「只給瀏覽器」的金鑰通道 |
| 請求體 | 建立時的 JSON | 源站看得到;部分代理會取樣 | 只放密文與非敏感後設資料 |
「零知識」在這裡的意思很窄:服務端存了也解不開。它不等於「什麼都不存」,也不等於「拿到完整連結的人解不開」。完整連結是持有即解密的憑證;少了 # 後面就解不開,多抄一份就等於多一把鑰匙。
用 Network 面板核對金鑰有沒有上線路
口號無法自證。下面這套步驟只依賴瀏覽器自帶的開發者工具,用來拆穿「連結裡有金鑰,所以伺服器一定看過」或反過來「頁面寫了本地加密,所以一定沒外傳」。目標不是形式化證明,而是確認這一次點選有沒有把金鑰放進 HTTP。
準備一條帶井號的測試連結。可以是你剛建立的焚鏈,也可以是任意本機頁面加上 #TESTKEY-只用於核對。先把 # 後面整段複製到記事本,後面要用來搜尋。
開啟 Network,勾選 Preserve log。Chrome、Edge、Firefox 都可以。過濾器先看 Fetch/XHR 和文件請求,再掃全部。Preserve log 避免跳轉清空記錄。位址列裡你仍看得到完整 URL,那是瀏覽器自己的顯示,不是發到網上的內容。
點開連結或回車導航。在請求列表裡點開文件請求和後續 XHR。看 Request URL:它應停在 # 之前。查詢裡可以有密文編號,不應出現你記在記事本裡的那串金鑰。
用金鑰子串做全面板搜尋。在 Network 搜尋框貼上金鑰,或其中一段不會碰巧出現在靜態腳本裡的子串。若沒有任何請求命中,說明至少這次導航沒有把 fragment 當作 HTTP 內容發出。
對照一次錯誤寫法。把同一串金鑰改到 ?key= 再訪問一次(用不會造成真實洩漏的測試值)。這次搜尋應能命中請求 URL。兩種結果並排,比任何示意圖都清楚。
建立動作再搜一遍原文。若你在焚鏈建立頁提交了一段僅供測試的假口令,用這段原文搜 POST 請求體。應命中密文欄位的形態,而不是原文本身;金鑰欄位也不該出現。閱讀頁對接收方公開,不必先登入。
這一步能證明什麼,不能證明什麼
Network 驗證的是:這次操作有沒有把金鑰或原文放進 HTTP。它看不到惡意擴充功能、被 XSS 插入的腳本,或公司 SSL 解密代理注入之後的頁面。對拆穿「金鑰寫在查詢參數裡」已經足夠;不要把它理解成端點安全證明。
Fragment 擋得住日誌,擋不住整條連結被轉發
把金鑰放在 # 後面,解決的是「源站和代理預設能讀金鑰」這件事。下面這些路徑仍然存在,寫進預期比印三個演算法字母有用。
完整連結就是持有即解密
誰拿到路徑加 fragment,誰就能在閱讀頁解開密文——直到它被焚毀或過期。聊天記錄、郵件歸檔、瀏覽器歷史、螢幕共享和肩窺,都不在 HTTP 規範的管轄裡。閱後即焚減少的是反覆開啟和服務端長期存明文,不能阻止對方截圖或再轉發出去。
Referer、預覽卡片、分析腳本
現代瀏覽器在發 Referer 時通常不含 fragment,但這條規則救不了「頁面自己把 location.href 打進分析事件」的實現。若建立頁或閱讀頁把完整地址當作埋點屬性上報,金鑰就從用戶端通道漏走了,伺服器 access log 乾淨也沒用。核對埋點請求時,用同一串金鑰再搜一遍。
即時通訊和郵件用戶端的連結預覽不一定保留 # 後面。有的抓取器只請求路徑,預覽失敗但金鑰仍在你貼上的原文裡;有的會改寫短鏈,把 fragment 丟掉,對方點開後只看到「連結不完整」。傳之前用無痕視窗自己點一次,確認閱讀頁能解密,比相信用戶端「原樣開啟」更可靠。
瀏覽器歷史與本地腳本
位址列裡的完整 URL 會進歷史。共用電腦或同步了歷史的瀏覽器配置檔案,等於留下一把過期前仍有效的鑰匙。XSS 或被劫持的腳本可以讀 location.hash:Web Crypto 保護的是誠實頁面裡的金鑰操作,不是「惡意腳本已經進了同源」。這些是端點與前端供應鏈問題,應和「服務端不該持有金鑰」分開處理。
哪些材料必須留在 # 後,哪些可以上伺服器
必須留在本機、只允許經 fragment 交給接收方瀏覽器的,是能直接還原明文的材料:對稱金鑰本身。一旦它進了查詢或請求體,零知識敘事就斷了。
可以離開裝置的,只有對服務端無用的資料:密文 blob、不可猜測的編號、過期時間和最大閱讀次數。MyPassGen 焚鏈單條內容上限 32 KB,適合口令、API Key 片段和短說明,不適合整份磁碟映象——大檔案應先在本機做成 .lock / .enc 再另傳。服務端按設計在首次成功閱讀後刪除密文;過期未讀也會刪。沒有服務端明文副本,連結丟了不能「找客服恢復」。
不要把「頁面請求了腳本」和「上傳了金鑰」混為一談。靜態資源請求是正常的。要找的是:金鑰子串有沒有出現在請求 URL、Query、Payload 或自訂標頭裡。本站也不會把金鑰或原文當作分析事件內容上報——事件裡不應出現秘密本身。
想把金鑰發給同事、又不想寫進伺服器日誌時
常見替代做法的侷限很具體。明文郵件和即時通訊會把口令留在雙方歷史、服務端歸檔和裝置備份裡,過期也刪不掉對方那一份。網盤預設對服務端可讀,除非你先在本機加密再上傳密文。把金鑰放在查詢參數裡,等於請反向代理幫你記一筆。這些路徑不是「不夠方便」,而是明文視窗被寫進了協議。
若你要傳的是短文本機密——root 口令、恢復碼、一小段連線串——需要的是:本機加密、金鑰不進 HTTP、接收方開啟即可看、看完密文消失。MyPassGen 的閱後即焚連結按這個約束做:AES-256-GCM 在瀏覽器完成,金鑰接在 # 後面,服務端只暫存密文;建立和閱讀都不必註冊。開啟 Network,按上文步驟搜一遍自己剛複製的金鑰,就能核對「日誌裡不該出現的那一段」有沒有上線路。
超過 32 KB 或必須留下可反覆解密的備份時,改用檔案加密盒在本機產生 .lock / .enc,再自己選擇傳輸通道。焚鏈解決的是「只該看一次的短秘密」,不是網盤替代品。關於敏感計算為什麼預設不該交給伺服器,上一篇為什麼要把加密計算放在瀏覽器本地把明文視窗拆得更開。本篇只要求你能回答:這條連結被點開時,金鑰還在不在井號後面,有沒有跑進請求行。