你的密码是否在数据泄露中?
数据泄露是指某个服务的密码数据库流落到公开场合——而泄露语料就是从数百起这样的泄露中收集的密码集合,经过索引,任何人都可以查询某个密码是否在其中。如果你的密码在里面,攻击者已经拥有它:它躺在字典里,被自动拿到每一个能登录的页面去试。本文解释这项检查如何在不透露密码的情况下工作、“出现过 5200 万次”到底意味着什么、为什么“未找到”不等于健康证明,以及为什么绝不能把密码粘贴进聊天机器人去问它是否安全。要运行检查,请使用密码泄露检查。
什么是泄露语料
每一起重大泄露都会留下同样的残留物:一个用户名和密码的数据库——通常以哈希形式存储——从一家公司的系统中被复制出来,流转、出售或公开。单独看,这些数据库只是一家公司失守的证据;收集到一起、去重并编入索引之后,它们就变成了别的东西——人们实际使用的密码的人口普查。Have I Been Pwned 的 Pwned Passwords 语料——本站检查器查询的那个——包含来自数百起泄露的十多亿个密码,并且每出现一起新泄露就会增长。它不是理论家编出来的弱密码清单,而是真实的人选择、输入并丢失的密码的记录。
这就是为什么语料是一面毫不留情的镜子。你花五秒钟想出来的密码——名字加出生年份、球队加感叹号、键盘上的连续按键加末尾一个数字——很可能已有成千上万的人以完全相同的形式想出来过,而如果其中任何人在某个被攻破的服务上用过它,它就在语料里。攻击者不会像人那样一次猜一个密码,他们玩的是撞库:拿一份泄露的用户名密码对清单,或一份泄露密码的字典,每小时自动尝试数百万次,对象是各处的登录页面。语料里的密码,就是已经在清单上的密码。
五字符检查如何工作
对照一个十亿条目的数据库检查密码,听起来似乎必须把密码发送给某个人——多年来,这一直是对每一项泄露检查服务诚实的质疑。解决办法是一种叫 k-匿名的技巧,一句话就能说清:服务永远不知道你问的是哪个密码,因为它看到的信息不足以分辨。密码在浏览器中用 SHA-1 做哈希,得到一个 40 个字符的指纹,只有该指纹的前 5 个字符会被发送给 Have I Been Pwned。服务返回所有共享这 5 个字符的指纹后缀——通常大约八百个——浏览器再在本地、在你的设备上查找自己的后缀。
5 个字符就是关键数字。5 个十六进制字符大约有一百万种可能,因此在十亿条目的语料里,每个前缀大约由一千个密码共享——相似者足够多,服务无法识别你的密码;又足够少,答案可以装进一次小小的响应里。密码本身没有任何信息经过网络:不是密码,不是它的完整哈希,甚至不是它长度的一点暗示。同样的设计也是这项检查不需要账号、不需要 API 密钥、不需要值得注意的速率限制的原因,也是响应可以缓存数周的原因:同一个前缀的答案,对每一个询问者都一样。本站的密码泄露检查正是在浏览器中实现这一模型,哈希在发送之前先在本地算好。
“出现 N 次”是什么意思——以及该做什么
次数大于零,意味着密码在泄露中出现过那么多次,而这个数字直接衡量了它会被多早尝试。数以百万计的次数——“password”本身出现过五千多万次——意味着这个密码是每一次撞库中最先尝试的猜测之一,应该在所有使用它的地方都换掉,先从那些保护着其他账户的账户开始:首先是邮箱,然后是银行,再然后是密码找回路径。次数很小也不算过关,即使只出现过一次,也说明这个密码已经在攻击者的字典里,而且通常还说明它遵循某种可猜的模式——正是这种模式让成千上万个相似密码也进了语料。
任何次数下的解决办法都是一样的:换成一个你在任何地方都没用过的唯一密码,保存在密码管理器里,而不是记在脑子里。人类记忆正是重复使用密码的原因——没有人能记住一百个互不相同的随机字符串——而管理器是让唯一性变得负担得起的工具。用密码生成器生成替代密码,保存进管理器,然后在所有用过旧密码的服务上逐一更换,先换那些能让攻击者重置其他账户的服务。如果同一个密码保护着好几个账户,就把它们全部当作已经暴露:攻击者会把泄露的密码拿到每一个能登录的服务去试,而不只是它泄露出来的那一个。
“未找到”不意味着什么
次数为零是个好消息,但有严格的限度。它只说明这个密码没有出现在该语料所知道的泄露中——仅此而已。它不说明密码强壮:一个由字典单词加数字组成的短密码可能不在语料中,却仍能在几分钟内被猜测攻破,因为猜测不需要密码先泄露。它不说明密码安全:泄露浮出水面需要数月甚至数年,一个躺在尚未上报的泄露里的密码,在曝光的那一天到来之前,对每一个语料都是不可见的。它也不说明重复使用的密码没问题:一个在十个网站使用的密码,只需一起泄露就会丢掉全部十个,无论今天的次数是多少。
诚实地理解零的方法,是把它看作几项检查中通过的一项。这个密码已知没有泄露——这一点值得知道,也是这项检查唯一能告诉你的事。它是否同时足够长、足够随机、只用在一个地方,是另一个问题,检查回答不了。值得坚持的标准是下面列出的 NIST 记忆秘密指南中的那条:重长度而非复杂性规则,绝不为定期而定期要求更换,并在密码被选定的那一刻对照泄露语料检查新密码——这正是本文描述的检查。一个长、随机、唯一、未找到的密码,就是一个好密码。去掉这四个属性中的任何一个,零的意义就不大了。
永远不要把密码粘贴进聊天机器人
问“我的密码安全吗?”最危险的方式,是把密码粘贴进聊天机器人或 AI 助手直接问它。聊天会保留对话记录:你的密码会被存到别人的服务器上,按对方的保留政策保存,被用来训练或调优模型,甚至可能在以后的回答中被原样引用——引给完全不同的另一个人。同样的道理适用于任何要求你在表单里输入密码并承诺帮你评判的网站:除非像本站检查器这样在本地做哈希并把机制展示给你,否则就默认密码正在被发送、存储和记录。泄露检查之所以值得做,正是因为它可以在不把秘密交给任何人的情况下完成——而当你把秘密粘贴进聊天去问它时,你已经制造了这项检查本要发现的那种暴露。
这条规则可以推广。密码、API 密钥、令牌和私钥,都是绝不能以原始形式输入聊天、工单、论坛帖子或共享文档的东西——这也是本站设有秘密脱敏工具、用于在分享之前把它们从文本中清除的原因,还有一篇配套文章在粘贴之前先脱敏你的秘密。当秘密确实必须交到他人手中时,通过秘密管理器或过期的单次查看分享链接发送,并且与讨论走不同的渠道。而当你需要知道某个密码是否泄露时,就用为这个问题而建的机制:本地做哈希,发送五个字符,剩下的在自己的设备上匹配。这就是全部的检查,也是唯一一种不会通过制造新的泄露来回答自己的提问方式。