VPN 客户端启动时出现的提示很容易被误读。它不是 VPN 账户密码,也不是隧道密码,输入它并不证明连接是安全的。它解锁私钥的一种存储表示,让客户端能够读取密钥材料并用它进行身份验证。此后发生的事情是另一个问题。

在实践中,答案往往在边缘处出错:人们以为口令保护着运行中的隧道,或者以为更改口令就能吊销已经泄露的密钥副本。这两种假设都不成立,而且都以让凭据继续暴露、操作者却以为已经处理完毕的方式失败。

一个对话框,几种不同的秘密

私钥口令解密一个文件。账户密码向服务验证你的身份。PKCS#12 导入密码解密一个包含密钥及其证书的捆绑包,它可能和密钥本身的口令不是同一个字符串。这些提示看起来几乎一样,而猜错哪个秘密该填哪里,正是密钥被粘贴到错误字段的原因。

隧道自身的加密是第四件事。数据通道使用握手期间协商的会话密钥;私钥口令对保护单个数据包没有任何作用。如果有人能读取密钥文件,他可以离线尝试猜测口令;但如果他能读取数据包,口令就无关紧要。

磁盘上的加密覆盖什么

加密的 PEM 密钥有两种形式,头部会告诉你拥有哪一种。现代 PKCS#8 形式以 -----BEGIN ENCRYPTED PRIVATE KEY----- 开头;旧式 PEM 形式在较老的 OpenVPN 配置中仍很常见,以 -----BEGIN RSA PRIVATE KEY----- 开头,并在其下方带有 Proc-Type: 4,ENCRYPTED 和一行 DEK-Info。文件保存着用你的口令派生出的密钥加密的私钥,通常使用基于密码的 KDF,并带有声明的迭代次数或工作因子。OpenSSL pkey 文档介绍了这些格式以及读取时适用的口令选项。

由此产生两个后果。弱口令可以按 KDF 允许的速度被离线攻击,所以即使文件已加密,文件权限和备份访问仍然重要。而只拿到文件、没有口令的攻击者只能猜测;同时拿到文件和口令的人就拥有了密钥,完全就像它从未被加密过一样。

head -3 vpn.key
openssl pkey -in vpn.key -noout -pubout
openssl pkcs12 -in bundle.p12 -info -noout

head -3 显示头部,在旧式文件上还显示证明加密的 Proc-Type 和 DEK-Info 行;仅一行并不能作为任何方向的证据。pkey 行会询问口令并只打印公钥那一半,这证明文件和口令可以正常工作,而不会暴露私钥。不要用 -text 做这项检查:它会打印私有组件 privateExponent、prime1、prime2 等,而该输出绝不能粘贴到任何地方,不能放进工单、聊天或日志。PKCS#12 命令还会告诉你捆绑包是否有单独的 MAC 或加密密码,在把它交给同事之前值得了解。

密钥加载后它就不再保护什么

解锁对该进程来说是一次性事件。客户端向 KDF 请求密钥,解密文件,并在需要期间把私钥保存在内存中。从那一刻起,口令对运行中的会话不再提供任何保护:不保护进程内存,不保护核心转储,不保护连接到客户端的调试会话,也不保护密钥使用期间创建的机器备份。

这与带口令的 SSH 密钥或密码管理器已解锁的保险库是同一道边界。它提高了静态文件被窃取的代价,但对以你的用户身份运行的恶意软件、请求客户端签名的授权应用,或能读取内存的管理员毫无作用。把它看作一层防护,而不是让密钥可以随意放置的控制措施。

为什么提示总是反复出现

每次重新连接都再次询问的客户端不一定坏了。有些客户端会为会话缓存口令,有些把它存进操作系统钥匙串,还有些可以指向提供口令的辅助程序,所以你遇到的行为取决于客户端及其配置,而不是密钥文件。

如果反复出现的提示才是真正的抱怨,请在移除密钥加密之前检查客户端的缓存和身份验证选项。去掉口令会把受保护的文件变成明文密钥,重新连接会变得安静,代价是你失去了唯一的静态控制。更好的答案通常是受支持的凭据存储,并配合你本来就会使用的文件权限。

丢失和暴露不是同一种修复

丢失的口令无法从证书中恢复。证书是公开材料,把一个名字绑定到一把密钥;它不包含回到私钥的路径,也不包含关于口令的任何提示。实际选择是密钥的授权备份,或通过运营方正常流程签发的新身份。任何提出“恢复”口令的人,都是在提出猜测它。

暴露需要不同的应对。用新口令重新加密同一把密钥不会改变密钥材料,所以已经在别处解锁的副本仍然有效。正确的修复是吊销或替换凭据:签发新的密钥和证书,分发它们,并在对端停用旧的。在此之前,更改文件密码只是日常维护,不是遏制。只有在确认新身份正常工作后,才把旧文件排除在备份之外,并记录是哪个序列号或指纹替换了它。

相关文章