你的 VPN 密码只和它的验证者一样私密
隧道加密只覆盖传输这一段。验证密码的组件仍然会收到它,而存储的哈希保护的是完全不同的后续阶段。
对任何 VPN 登录依次问四个问题:传输途中谁能保护密码,哪个组件会收到它,该组件拿它做什么,之后又存储了什么。每个答案对应不同的控制,一个答案再强也不代表其余。错误在于把隧道加密当成覆盖了全部四项。它只覆盖第一项,而且仅覆盖第一项。
要问谁终止会话,而不是会话是否加密。
究竟是对谁加密?
TLS 保护的是客户端与终止连接者之间的密码。如果那个端点就是 VPN 网关,网关的认证代码就会看到明文密码,校验它,然后把密码本身或派生值继续传下去。这是有意的设计,不是泄露。路径上的网络观察者学不到有用的东西,而负责验证的组件会得到它需要的一切。
OpenVPN 社区明确记录了这一点:auth-user-pass-verify 会把提交的凭据交给验证脚本或插件。这是组件之间有意的交接,它作为具名参与方属于信任模型。
验证者看得到密码
组件一旦收到密码去验证,口令是否留在内部,就取决于该组件的访问控制、日志记录和代码质量。把凭据写进日志的脚本,或缓存凭据的插件,造成的暴露远大于协议本身。访问权限取决于架构与角色,而非隧道,所以控制验证者的服务负责人也应纳入评估。
不同方法暴露的材料不同。证书认证无需发送私钥就能证明持有私钥,联合身份流程可以把密码留在身份提供方,同时向 VPN 签发限定范围的断言。这些设计缩小了圈子,但没有一个能消除所有受信任方。
存储的哈希保护的是另一个阶段
NIST 的指南把受保护的传输与抗攻击的验证者存储区分开来。加盐与带成本的哈希方案应对的是存储型验证者威胁,也就是数据库泄露之后才会发生的事。它们对运行时必须收到输入才能比对的组件毫无作用。把指南读成承诺运行时保密,是范畴错误。
因此,一个良好哈希的密码库和一个暴露的验证脚本可以在同一产品中并存而不矛盾。
选择一种能缩小圈子的方法
如果要求是网关永远收不到可重复使用的密码,就选一种真正能保证这一点的方法;更换数据密码并不会产生这种性质。验证 VPN 服务器的证书只能告诉你到达了哪个对端,并不能说明该对端之后如何处理凭据。保留服务器验证,按服务使用不同凭据,并遵循组织支持的标识流程。
记录收到密码的一方、校验密码的一方,以及密码以什么形式保留。这三个答案应当写在连接配置旁边,因为它们比任何具体隧道都活得久。
有用的问题不是密码是否加密,而是它向谁隐藏、哪个组件收到它,以及之后还剩下什么形式。