VPN 自签名证书与公共 CA:究竟改变了什么
自签名证书和公共证书以同样的方式加密 VPN 隧道。真正的区别在于谁为服务器背书,以及谁必须信任这一声明。
你打开一套 VPN 配置的证书页面,看到免费的自签名选项与付费的公共 CA 并列,这个问题听起来像是安全选择。其实它是受众选择。两种方案用相同的底层原语加密隧道,而且一旦私钥泄露,两者都会变得毫无价值。真正区分它们的是:谁对服务器身份作出声明,以及谁有条件核验这一声明。
证书承担着两项常被混淆的工作
证书把公钥绑定到一个名字,而密钥负责加密与签名。证书上的签名是一份单独的声明:某个权威机构核实过,这个名字属于此密钥持有者。 自签名证书只是对自身作出这一声明,因此根本不构成第三方主张。
公共网站需要第三方版本,因为访客在没有既有关系的情况下到访,依赖浏览器的信任存储。VPN 客户端不是陌生人。你在它安装的配置文件里提供 CA 证书,或固定服务器证书,因此校验恰好针对你所选择的权威机构进行。要让这项检查有意义,并不需要任何商业 CA 参与。
最终会话的强度来自密钥长度与密码套件,而不是签名者。所以把自签名证书称为“加密更弱”完全是错的;它只是被担保的范围更小,那是另一种属性。
公共 CA 的收费换来了什么
最清楚的情形是管理页面。如果同事、承包商或任何没有预置配置文件的人都必须在没有浏览器警告的情况下打开 VPN 服务器的网页界面,公共受信任证书就消除了这种摩擦。浏览器本来就信任签发者,因此无需导入任何东西,也无需解释。
这种便利有代价,值得在购买前说明。续期必须自动化,否则站点会按时间表失效;公共证书会在证书透明度日志中暴露主机名;签发速率限制会惩罚过于频繁重试的脚本。这些都不是回避公共 CA 的理由,但它们属于运营工作,而私有 CA 会把这类工作挪到别处。
公共证书不做的事,是认证你的用户。客户端身份是另一项决定,用客户端证书、密码或第二因素来实现,而给服务器签名的 CA 对“谁可以连接它”不置一词。
私有 CA 适合 VPN 的场景
对于客户端集合已知的私有 VPN,运行自己的 CA 是常规选择。你一次性创建 CA,用客户端将要使用的名字签发服务器证书,并在每个配置文件中分发 CA 证书。随后每个客户端都依据你的权威机构校验服务器,外部任何一方都不会得知主机名。
代价真实但有限。有人直接打开管理页面时浏览器会警告,因为浏览器没有理由信任你的 CA。配置文件的分发成为入职流程的一部分,而轮换 CA 意味着要触达每一个客户端。对十个或五十个已知用户的服务来说这是可接受的代价,对拥有数千用户的公共端点则很痛苦。
有一个条件让整套安排成立:校验必须真正发生。被配置为忽略证书错误的客户端会接受任何出示任何证书的服务器,于是身份保证消失,而加密仍然存在。这个设置才是多数“自签名不安全”说法中真正的弱点。
CA 私钥决定了你以后能做什么
意外通常几个月后到来,当你想添加一台设备时。签发客户端证书需要 CA 私钥,生成吊销列表同样需要。如果你继承的服务器里有证书和密钥文件,却没有 CA 密钥,你就无法签发任何新东西。你的选择是重建 PKI 并给每个客户端发一份新的 CA 证书,或者改用密码认证——那是另一种安全模型,也无法挽回已失去的东西。
同一个领域里还有两个更小的陷阱。easy-rsa 脚本假定你站在包含它们的目录里,所以“找不到文件”的错误通常意味着位置不对,而不是安装损坏。而仅使用证书的设计完全正当:你可以要求客户端证书而不使用预共享密钥,前提是每个客户端各有一份,且服务器会校验证书链。
为每台设备签发一张证书,而不是给整个团队共用一张客户端证书。这样丢失一台笔记本只需要吊销一张,而不是给所有人重发。
检查你继承了什么
在规划任何变更之前,先读一读你已有的证书:
$ openssl x509 -in server.crt -noout -subject -issuer -dates
subject=CN = vpn.example.net
issuer=CN = vpn.example.net
notAfter=Nov 3 09:00:00 2027 GMT
$ openssl verify -CAfile ca.crt server.crt
server.crt: OK
如果签发者与主体相同,该证书就是自签名的,这是设计选择而非缺陷。日期会告诉你续期何时成为某个人的问题,而针对你打算分发的 CA 做一次成功校验,能在第一个客户端尝试之前确认证书链工作正常。
然后就受众与分发方式来选择:当未知浏览器必须信任管理页面时用公共 CA;当每个客户端都收到你控制的配置文件时用私有 CA。两种答案在加密强度上没有高下之分。