锁形图标背后的证书早就宣布了你还没上线的那个页面

一个竞争对手在团队悄悄测试完同一个城市页面后的一周内就上线了一模一样的城市,广告都还没买一条,链接也没发一个。某位运营者从论坛上一个陌生人那里得知,有人摸到了一个登录页面,而这个页面本不该被公司外的任何人知道存在。这两种情况看起来都不像是员工泄密、邮箱被盗,也不像是运气问题。它们通常都能追溯到一个更平常的原因,一张自动签发的安全证书,正做着它本该做的事。
这个机制叫Certificate Transparency,证书透明度,它和黑客入侵毫无关系。这是一份自2018年起就存在的公开且永久的HTTPS证书档案,免费可查,而且它已经完整记录了这个网站,或任何网站,曾经放在一张无浏览器警告的证书背后的每一个主机名。几乎没有运营者查过自己在这份档案里的记录。这才是真正该补上的缺口:它不是通常意义上的漏洞,而是一份一直公开却从未被当成公开资料对待的档案。
证书在签发的那一刻,悄悄变成了什么
自2018年起,一张被公开信任的证书,也就是让Chrome和Safari显示一个简单锁形图标而不是警告的那种证书,必须被记录进若干Certificate Transparency日志之一,否则这些浏览器就不会信任它。苹果在同一年晚些时候为Safari加上了同样的要求。这并不是专门针对成人网站或分类广告目录设计的,它的目的是防止有人偷偷为别人的域名签发一张假证书并借此截获流量。这个机制的副作用是,日志同时也会记录下一个网站为自己申请的每一张真实证书,而这份记录从一开始就从未被设计成私密的。
日志会按名称列出一张证书实际覆盖的每一个主机名。一张签发给admin.example.com的证书,就会原样显示这个名字,明文记录,永久保留。背后那个页面是否曾被网站菜单链接过、在站点地图里提到过,或者被搜索引擎收录过,都无关紧要。证书颁发机构在签发的那一刻就记录了它,不管这家机构是Let's Encrypt、Cloudflare,还是大多数主机面板内置的自动证书管理工具,因为它们都遵循同一套浏览器规则。
查一下这个不花一分钱,不到一分钟就能完成。一个叫crt.sh的免费工具,让任何人输入一个域名,就能看到为它签发过的每一张证书,不需要账号,也不需要注册。输入竞争对手的域名和输入自己的域名效果完全一样,正是这一点,把一份例行的技术记录变成了一项商业风险。任何读到这里的运营者现在就可以打开那个页面,第一次看到自己的域名已经向全世界透露了什么。
这里有一个真正的例外,它对接下来的内容很重要:通配符证书,也就是覆盖整个模式,比如*.example.com,而不是一个具体名字的那种,日志里只会记录这个模式本身。真正在用它的具体主机名,比如newcity.example.com或staging.example.com,并不会以名称的形式出现在日志里。而专为某一个具体子域名签发的证书,则始终会以名称出现。这个差别正是运营者手里真正能用上的杠杆,下文还会再谈到它。
这件事实际上把什么交到了陌生人手上,具体有三种方式
第一种是扩张计划的时间点。一个新城市或新国家的页面,几乎总是在营销部门准备好宣布之前的几天或几周,就在自己的子域名上搭建并测试完毕,而用HTTPS测试这个子域名,就意味着它的证书恰恰是在那段安静的筹备期内签发的,而不是在上线当天。基于同一份公开日志建立的免费监控工具是存在的,它们会在被监控域名出现新证书后的几分钟到几小时内通知使用者。一个已经知道主域名,而主域名按定义本来就是公开的,的竞争对手,根本不用去猜新城市的名字。他只需要盯着看,日志就会在官方公告发出之前把答案交给他。
第二种是内部工具的分布图。这种规模的目录网站通常会有一个员工登录页面、一个供审核人员处理广告的队列,也许还有一个给外部支付服务商用的独立面板。如果每一个都拿到了自己专属的、名字一看就懂的证书,admin、moderation、billing,这份日志现在读起来就像一张建筑平面图。而这张平面图,正是之前已经讨论过的那类入侵的起点,那种入侵的常见方式往往不是什么惊天动地的漏洞利用,而是把一个重复使用的密码拿去试那个最容易找到的登录页面。一个描述性命名的子域名本身并不会导致这种入侵,但它省去了攻击者本该花时间的那一步,先找到登录页面在哪里。
第三种是一段谁都无法收回的历史。日志不会遗忘任何东西。三年前的一个测试子域名、为一个早已不存在的合作伙伴搭建的短命页面、开发者本打算删掉却忘记了的一份测试环境副本,这一切都会永远留在日志里,哪怕证书早已过期,哪怕指向它的DNS记录早已被删除。今天在crt.sh上搜索一个域名,可能会挖出现在团队里没人记得创建过的名字。真正危险的不是那条记录本身,而是那个地址背后曾经响应请求的服务器很可能还在那里,从未更新过,因为所有人都以为删掉链接就等于关掉了它。
这一切都不需要大多数人所说的那种黑客技术。只需要知道有一个免费的搜索框存在,然后往里面输入一个域名,这正是为什么它值得被认真对待,而不是被归到别人才需要操心的安全问题里。
什么都阻止不了这件事,而什么才真正有用
人们很容易想借用那套管理搜索引擎如何看待网站的工具,但在这里没有一个用得上。这个目录网站已经在哪些爬虫能看到哪些页面上做出的选择,走的是robots.txt和搜索引擎收录这条路线,这和证书日志完全是两套不同的系统,后者从未听说过前者。屏蔽一个爬虫、把一个页面从索引里撤下,或者给它标上noindex,都不会改变它的证书是否会出现在日志里,因为日志记录的是证书本身,而不是这个页面对搜索引擎的可见性。
也没有任何合法途径能拿到一张在访客浏览器里无警告运行、同时又不进日志的证书。要求主机提供商或证书颁发机构网开一面,等于要求一件对面向公众的业务来说根本不存在的东西:唯一能豁免被记录的证书,是由一个私有的内部证书颁发机构签发的,而普通访客的浏览器压根不会信任这种机构,这让它对任何客户或广告主真正需要打开的东西都毫无用处。
事后重命名或删除一个子域名同样解决不了任何问题,因为日志里那条旧记录会原封不动地留在原地。对一个已经以这种方式被记录下来的名字,不存在任何追溯性的清理手段:运营者真正能改变的,只有从现在开始发生的事。
真正有用的,是前面提到的那种通配符证书,而且要刻意使用。内部工具、测试环境副本,以及公开上线前正在测试的一切,都应该放在一张覆盖整个模式的证书背后运行,而不是每次都为它单独签发一张有名字的新证书。大多数主机面板和内容分发网络,在新增一个子域名的那一刻,默认就会自动签发一张带名字的证书,这只是因为这个默认设置实现起来更简单,而不是因为它更安全;要求主机提供商或开发者,把这个具体设置改成只对非公开营销页面才用通配符,是一个具体的、可以核实的要求,而不是一句含糊的加强安全呼吁。
第二个真正有效的办法,是别再把一个不起眼的名字当成一把锁来依赖。登录页面、审核队列或账单面板,无论叫什么名字,都需要一道真正的密码验证,理想情况下还应限定在一组已知的办公室或员工地址范围内,因为名字从来都不是找到它们的唯一方式:还有别的技术手段可以挖出一个网站的子域名,这些手段跟证书完全无关。把一个难猜的名字当成主要防线,才是这里真正的错误,而不是证书本身的选择。证书的选择只决定了这个名字会不会在任何人都还没去找它之前,就被免费送了出去。
这一周真正该核查的事
第一步不花钱,只要五分钟:打开crt.sh,输入这个网站自己的域名,把返回的全部清单读一遍。任何认不出来的记录,都值得直接去问负责主机的人:这个东西还在运行吗,如果还在,为什么今天整个公开互联网都知道它的地址。
对于清单里查出来是已废弃功能、已结束的测试,或者是为一个早已不存在的合作伙伴做的项目,解决办法不只是删掉DNS记录。那个地址背后曾经运行的东西,应该在服务器层面彻底关停,确认它对任何请求都不再响应,而不是只拆掉指向它的那块牌子,却任由它在背后悄悄继续运行。
对于下一次新城市或新国家的上线,测试阶段应该放在一张通配符证书或者一张共用的内部证书背后运行,而不是用一张写着那个城市具体名字的证书,这样日志才不会在营销部门之前就把扩张计划公布出去。这只是一项需要在下次上线前跟开发者或主机提供商确认的设置,不是要重建任何已经在运行的东西。
对于今天已经在运行的每一个内部登录、审核或账单页面,问题不在于它的名字是否难猜。问题在于,不管叫什么名字,它前面是否真的挡着一道密码,以及有条件的话是否有地址限制,因为这才是名字本身已经公开之后真正靠得住的东西,而查过crt.sh之后就会发现,它多半早就已经公开了。


