问题
这两天按以前的做法给一个新域名加Let's encrypt证书,如下:
certbot run --nginx --email <your_email> -w /<path_to>/challenges -d <your.domain.name> --preferred-challenges tls-sni --renew-by-default --agree-tos
复制代码
结果报了这么一个错误:
Client with the currently selected authenticator does not support any combination of challenges that will satisfy the CA.
放狗搜了一番,才知道原来是因为ACME的tls-sni验证被曝了一个安全问题:
2018.01.09 Issue with TLS-SNI-01 and Shared Hosting Infrastructure
所以这个方式不能用了。
原理说明
基本上就如上面那个官方说明所说,tls-sni验证的方式是:
- 客户向let's encrypt申请其域名的证书,let's encrypt随机生成一个无效域名
- certbot在客户服务器上创建一个此无效域名的自签名证书,并启动一个此域名的https服务
- Let's encrypt的服务器连接客户端的IP,并通过SNI申请验证此无效域名的证书
- 如果验证通过,则认为这个客户身份有效
- 给此客户签发其域名的有效证书
这里的漏洞在于,某些主机服务商存在多个用户共用一个IP的情况,如果有人知道某个域名指向的服务器与自己所在同一个IP,即可利用tls-sni的这个漏洞取得不属于自己域名的有效证书,即可用于类似中间攻击之类的恶意用途。
所以在没有找到解决方案之前,let's encrypt关闭了tls-sni验证方式。
影响
对于大部分用户来说,影响不大,只要把验证方式从tls-sni改为http即可。
但是这就要求服务器可以同时提供80端口的访问,这对于某些只开放443端口的服务器就不方便了。
还有一个方法是用DNS验证,但这又需要域名注册商支持。
由于国内的ISP最近把443也关闭了,所以实际上http和tls-sni两个方法都已经行不通了,只剩下DNS方式可用……
谁叫你不幸生在中国——何作庥