连接对话框提供了一个记住登录信息的复选框,勾选后账户信息就从用户脑子里搬到了机器上。界面从不说它存在哪里。在 Windows 上,候选位置是当前用户的注册表区域、已经带有登录信息的配置文件,以及自动化脚本所做的一切。每个位置的读取者、失效方式和清理方法都不同,所以有用的问题是:哪个进程能取回这个秘密,能取回多久。顺着复选框从对话框往外查,再判断一台丢失的笔记本究竟暴露了什么。

从连接对话框的复选框开始

记住的值按配置文件和 Windows 账户保存在用户配置单元中,而不是共享的机器存储里。所以同一台电脑上的第二个用户看不到已保存的登录信息,也所以重装客户端未必会清掉那条记录。

配置文件本身只保存服务器、端口和设置,不保存密码,所以人们往往先查错了对象。因此删掉配置文件只是移除了连接,凭据仍留在原处。这是清理时最常见的意外。两样都要删,而不是只删一样。

注册表值透露了什么

账户名以可读文本存在,任何以该用户身份运行的进程都能直接解码,不需要特殊调用。密码不同:它由 Windows DPAPI 封装,绑定到账户,并且视标志而定还绑定到具体机器。因此把封装块搬到另一台电脑重放,并不能得到可用的秘密。

列出这些值就能回答运维问题,而无需触碰秘密本身。确认条目是否存在不需要解密任何东西。这份清单也可以当作清理前后的记录。

reg query "HKCU\Software\OpenVPN-GUI\configs" /s
cmdkey /list | findstr /i vpn
reg query "HKCU\Software\OpenVPN-GUI" /s | findstr /i "username password"

有两条边界值得直说。同一登录会话内的进程可以调用客户端所用的同一套解封例程,所以封装只是静态保护,挡不住已被入侵的桌面。而在没有全盘加密的情况下,封装值的私密程度只等于磁盘。

当配置文件里已经带有登录信息

有些门户下发的配置里直接写着账户名和密码,客户端于是静默连接。此时文件就是一份可用的凭据,它的每一份副本都是同一扇门的另一把钥匙。

这类文件会进入备份、聊天记录和同步文件夹,而原件的删除并不能让这些副本失效。修改本地文件对其他副本毫无影响。撤销访问意味着在服务器上修改密码,而且要尽快。一台笔记本上的清理是另一件更小的任务。

在提示可以接受的地方,优先用提示,并使用客户端的缓存设置。如果确实需要预填的配置文件,把它放在同步文件夹之外,任务结束后删掉。

自动化会把秘密挪到别处

脚本又引入了两个通道:进程参数和合成按键。命令行里点名的文件对任何能读进程参数或文件权限的东西都可见,而工具键入的密码会进入当前拥有焦点的窗口。有一个公开的例子就是在启动客户端前这样键入桌面密码。保存下来的一次性密码种子同样需要当心,因为它能生成今后所有的验证码,而且比一次登录活得更久。

更好的做法是把秘密放在只有服务账户能读的地方,依靠客户端有文档记载的重试与凭据来源选项,并避免在提权提示中注入键入。如果脚本为了提权需要桌面密码,那是权限设计问题,而不是 VPN 问题。

设备丢失之后的清理

先吊销或停用服务器上的账户,因为本地删除无法让已经被人拿到的副本失效。然后清掉记住的注册表值,删除配置文件和任何凭据文件,并在 shell 历史和脚本目录里搜索粘贴过的密码。

记下删除了什么、访问何时终止。这两项回答了事件复盘唯一要问的问题:设备离开后,是否还有凭据副本能用。

相关文章