首页 密码生成器 密码检测 隐私清洗 阅后即焚 文件加密盒

为什么解密密钥要放在 URL 的 # 后面

一次性传密最容易踩的坑,不是算法名字写错,而是把密钥放进了查询参数。浏览器按 URI 规范不会把 # 后面的片段发给服务器;access log 里通常只剩路径。下面把可见范围拆开,并给出你能当场核对的步骤。

运维把数据库口令发给同事,最省事的写法是一条能点开的链接。麻烦在于:这条链接一旦被点,中间会经过浏览器、反向代理、源站和一堆日志。你真正要控制的,不是「加密听起来安不安全」,而是解密密钥出现在哪一层

如果密钥写在 ?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。

01

准备一条带井号的测试链接。可以是你刚创建的焚链,也可以是任意本机页面加上 #TESTKEY-只用于核对。先把 # 后面整段复制到记事本,后面要用来搜索。

02

打开 Network,勾选 Preserve log。Chrome、Edge、Firefox 都可以。过滤器先看 Fetch/XHR 和文档请求,再扫全部。Preserve log 避免跳转清空记录。地址栏里你仍看得到完整 URL,那是浏览器自己的显示,不是发到网上的内容。

03

点开链接或回车导航。在请求列表里点开文档请求和后续 XHR。看 Request URL:它应停在 # 之前。查询里可以有密文编号,不应出现你记在记事本里的那串密钥。

04

用密钥子串做全面板搜索。在 Network 搜索框粘贴密钥,或其中一段不会碰巧出现在静态脚本里的子串。若没有任何请求命中,说明至少这次导航没有把 fragment 当作 HTTP 内容发出。

05

对照一次错误写法。把同一串密钥改到 ?key= 再访问一次(用不会造成真实泄露的测试值)。这次搜索应能命中请求 URL。两种结果并排,比任何示意图都清楚。

06

创建动作再搜一遍原文。若你在焚链创建页提交了一段仅供测试的假口令,用这段原文搜 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,再自己选择传输通道。焚链解决的是「只该看一次的短秘密」,不是网盘替代品。关于敏感计算为什么默认不该交给服务器,上一篇为什么要把加密计算放在浏览器本地把明文窗口拆得更开。本篇只要求你能回答:这条链接被点开时,密钥还在不在井号后面,有没有跑进请求行。