纯浏览器加密,零依赖实现秘密分享

七月 18, 2026 web-crypto end-to-end-encryption javascript security cryptography secret-sharing browser-api

用浏览器原生 API 做端到端加密分享敏感信息

说实话,网上传个密码真是让人提心吊胆。

邮件发完赶紧回去删,Slack 传完后悔一辈子,用第三方工具又怕人家后台看你的数据。有没有一种更靠谱的方式?

还真有。而且用浏览器就能实现。


第三方服务的问题在哪

OneTimeSecret 这类工具开创了"阅后即焚"的玩法。粘贴秘密 → 生成一次性链接 → 对方看完 → 没了。听起来很美。

但有个问题大多数人没想过:你的数据到底经历了什么?

就算号称"临时"服务,你的明文信息往往还是要经过他们的服务器。他们说不会看,说会删。但既然都是"承诺",为什么不直接把可能性消灭掉?

这就是端到端加密(E2EE)的价值所在。真正的 E2EE 下,服务器根本看不懂你的秘密。它存的只是密文——没有密钥的话,就是一堆无意义的随机字节。服务器就是个临时仓库,不是你的秘密管家。


端到端加密的秘密分享是怎么运作的

举个例子:Bob 想把数据库密码传给 Alice。

妙就妙在:加密全在 Bob 的浏览器里完成,在任何数据接触服务器之前就已经是密文了。

流程是这样的:

  1. Bob 输入秘密内容,选一个口令
  2. 浏览器用这个口令派生出加密密钥
  3. 秘密在本地用密钥加密
  4. Bob 把链接(包含密文和盐值)发给 Alice,口令通过另一条渠道传过去

为什么要分开发?因为如果链接和口令走同一条路,被人截了链接就全暴露了。链接走 Slack,口令走 Signal,或者短信,甚至物理纸条都行——关键是两条不同的攻击面

Alice 打开链接,输入口令,浏览器重新派生密钥,本地解密。整个过程服务器从来没见过明文。


技术原理:其实没你想的那么复杂

这块稍微硬核一点,但我尽量说人话。

口令怎么变成密钥:PBKDF2

人天生不擅长生成随机、高熵的密钥。我们喜欢设"password123"然后觉得自己很安全。

所以需要一个函数,把弱口令转换成强密钥——故意慢的那种。

PBKDF2 就是干这个的。它把你的口令加上一段随机盐(盐是公开的),跑 60 万次 SHA-256 哈希。暴力破解的话,每猜一次都要耗 CPU 时间。60 万次迭代下来,破解一个普通口令变得不切实际。

async function deriveKey(passphrase, salt) {
  const keyMaterial = await crypto.subtle.importKey(
    "raw",
    new TextEncoder().encode(passphrase),
    "PBKDF2",
    false,
    ["deriveKey"]
  );
  
  return crypto.subtle.deriveKey(
    {
      name: "PBDF2",
      salt: salt,
      iterations: 600_000,
      hash: "SHA-256"
    },
    keyMaterial,
    { name: "AES-GCM", length: 256 },
    false,
    ["encrypt", "decrypt"]
  );
}

实际加密:AES-GCM

真正加密用的是 AES-256-GCM。不是你可能在教科书里见过的那种 AES——这是带认证的版本。

GCM 模式不仅加密数据,还生成一个认证标签。如果有人在传输途中改了密文,解密会直接报错,不会悄悄吐出乱码。

每次加密还需要一个唯一的初始化向量(IV)。可以理解为另一个"盐":公开、随机、但对安全至关重要。

AES-GCM 是硬货,美国国家安全局推荐用于机密信息的那种。

async function encrypt(plaintext, key) {
  const iv = crypto.getRandomValues(new Uint8Array(12));
  const encoded = new TextEncoder().encode(plaintext);
  
  const ciphertext = await crypto.subtle.encrypt(
    { name: "AES-GCM", iv: iv },
    key,
    encoded
  );
  
  return { iv, ciphertext };
}

零依赖的意义

这个方案挺激进的:不用 npm 包,不用加密库,不用信任第三方代码。

用的都是浏览器内置的 Web Crypto API。这套标准从 2015 年就开始推广了,现代浏览器全都支持。实现方是 Apple、Google、Microsoft、Mozilla 这些大厂,他们花了大功夫做正确、实现时间常数化的版本。

想想那些依赖一堆包的项目。Log4Shell 就是因为依赖出的事。left-pad 事件让半个互联网挂了也是因为依赖。每次 npm install 其实都是在做信任决策。

用 Web Crypto API,你信任的是浏览器原生实现。攻击面比信任某个每周下载量几百万的 npm 包小多了。


后端:傻存储就够了

后端只存这些:

  • 密文(没有密钥就是废铁)
  • 盐值(公开的,密钥派生需要)
  • IV(公开的,解密需要)
  • 元数据(创建时间、过期时间、查看次数)

Redis(或 Valkey)配置 save ""appendonly no——完全不做持久化。进程一挂,数据全没。配置好 swap,防止任何数据落到磁盘。

服务器变成了一个临时的加密 blob 存储。它执行访问规则(一次性查看、过期删除),但就算想看内容也看不了。


能用在哪

直接嵌入到任何 web 应用里。加点表单、加几段 JS 函数,你的应用就有了安全的临时秘密分享功能。后端几乎不用改——服务器只管存取加密 blob。

这特别适合:

  • 内部工具临时分享凭证
  • 客服系统传输敏感数据
  • 开发者分享 API 密钥或数据库密码

秘密在密码学上跟你的基础设施隔离了。就算有人拿下你的数据库,拿到的也只是没有口令就解不开的密文。


权衡利弊

PBKDF2 跑 60 万次迭代比 Argon2 慢?这是事实。Argon2 是目前密码哈希的金标准,但 Web Crypto API 暂时还不支持。

但想想使用场景:一次性秘密,通常几分钟内就被看了。计算成本完全能接受。

稍微弱一点的 KDF 换来零依赖——对大多数场景来说值了。你又不是在保护核弹发射密码,共享的数据库密码明天就改了。


自己做,不要盲信

端到端加密的好处就是:你不用信任服务提供方。

代码可以审计。可以自己部署。可以验证服务器真的从来没接触过明文。

在这个数据泄露天天上新闻的世界里,做出让服务器在密码学上"看不见"数据的系统,不只是炫技——是负责任的做法。

下次要在网上传敏感信息,记住:保护数据最好的方式就是让它在加密状态下离开用户的手。Web Crypto API 给你提供了工具,就在浏览器里,原生支持,即拿即用。

Read in other languages:

FR ES DE DA EN