帐号安全:保护,隔离,整理


除了你的密码管理器,你应该假设所有使用密码的地方都明文存储密码。

前几天 noarch 被我所在教育局的网课系统吓了一跳。

有一天网课时,一个同学转告给老师称另一个同学忘了网课系统的密码,无法出勤网课,并请求老师重置密码。老师,之前也没有使用这个平台的经验,瞎摸索着,看哪里能重置学生的密码。然而这引出了一个意外发现:他可以查到所有班上学生的网课平台密码,并将其用邮件发给了那个丢失密码的同学。这件事发生时,老师还望着一些同学的奇怪密码感叹...

下课后,noarch 还对这件事半信半疑,认为这是一场闹剧。直到 noarch 匿名在这个被北美诸多教育局使用的平台注册了一个试用帐号,才意识到了问题的严重性:教师真的可以查到所有学生的明文密码。

如果你对上面的故事感到一头雾水,noarch 给你介绍一下密码存储的来龙去脉。

密码及密码存储的历史

根据 Wikipedia, 密码在古罗马就出现了,一开始用于在军队中交换暗语。同样地,密码在计算机应用之初就被广泛使用。

noarch 现在请你想象一个情况:黑客骇入了一个密码数据库,这个密码数据库中存储着所有用户用于登录这个服务的邮箱和密码。

你应该不难想象到,这些账户信息将全盘被黑客获取。这种行为叫做“拖库”。“拖库”意即将数据库导出,但在这里是从被黑的服务器上下载(通常用于存储密码和敏感个人信息的)数据库。

不过你可能没想到另一个黑客们会做的事:他们会将从一个地方获取的密码在其它地方尝试,并由此获取这一批用户在其它服务的密码。这叫做“撞库”。故名思议,“撞库”拿一个数据库中的数据向另一个数据库“撞”(尝试),并由此得到更多数据。

获取这些数据的目的当然是盈利:例如黑产者偷到了一个游戏的用户数据库,他们可能会“盗号”并变卖受害者的装备。这称之为“洗库”,即压榨数据库的金钱价值。

最后,这些经过“拖”、“洗”、“撞”的数据库会在一个点相聚:“社工库”。这些是包含了一群人众多帐号信息的数据库。

如果 noarch 出现在了这个数据库中,这个数据库会包含 noarch 的 Telegram 帐号、邮箱帐号、Matrix 帐号、Instagram 帐号... 并且明确标识,这些帐号都属于 noarch 一个人。它可能还包含所有社交工程攻击者想要的,在线上“出道”或是在线下抓捕、绑架或谋杀(如果它包含 noarch 的详细住址)noarch 的信息。参考

作为服务提供商,他们当然想了很多办法,使数据库即使被黑客访问,也不会全盘崩溃。

防拖库:Hash, 加盐

前面提到,黑客在拿到数据库的访问权限那一刻,整个数据库中的用户名和密码都将清晰可读。除了增强数据库的安全,使得黑客难以骇入以外,还有什么方法能让他们即使访问了数据库,也无法获得有效的密码呢?

答案是不直接存储密码,而是存储经过一些不可逆算法,从密码衍生出来的数据。用来这么做的不可逆函数称为密钥派生函数,它们输出的结果叫 Hash.

这样做为黑客们带来了一个明显的难题:他们将无法直接将这些密码到其它服务上尝试。这是因为其它的服务在收到这些 Hash 之后,会进行另一轮(实际应用中可能高达数万轮)变换,而这些 Hash 再次进行变换后将产生一个不同的值。

不过,道高一尺,魔高一丈:既然没法从 Hash 反推出密码,那么我就从零开始,从密码推出 Hash, 并记录它们的对应关系。如果我在数据库中遇见一个已知的 Hash, 那么我一定知道这个帐号的密码。随之而来的还有多种高效存储 Hash 和密码关系的方法,例如彩虹表,它可以在有限的存储空间内列出高达 1~8 位数字字母符号混合密码及其 Hash 的关系。

应对彩虹表也有一套办法:作为服务提供商,他们无法强迫既有用户将弱密码修改成更难破解的,十几位的强密码;于是加盐出现了。“盐”的比喻在这异常恰当:“加盐”指在既有的明文密码上加入一堆固定的明文数据,并将明文密码和这个附加的明文数据一起生成 Hash 并存储。验证密码时,加入这同一套盐,并与数据库验证密码加了盐后的 Hash. 这有如在烹饪时,加的盐都是 NaCl4, 然而加了盐后的菜式口味大不相同。

进行了加盐和 Hash 后的密码存储难以被破解。这是因为加盐使得密码长度大大增加:例如黑客可以轻易在一个彩虹表中存储密码 000000999999, 然而黑客难以存储 000000a^o2iH&JD$sO1gV8;7999999a^o2iH&JD$sO1gV8;7 的密码 / Hash 关系。

Hash 和加盐不能防范的

如果你本身就使用一个弱密码(例如短密码 2333, 或常见组合 password, qwerty, abcd1234 等),加盐无法为其提供应有的保护。“盐”通常是固定的,并且黑客一般知道这个“盐”;而弱密码本身就受暴力破解的威胁,黑客只需尝试加了相同“盐”的弱密码,即可获取一个有限但常用的 Hash 列表。

因此,要保证帐号安全,你必须设置一个强密码,它最好长度大于 20 个字符,由至少数字字母符号组成。

防洗库和撞库

如果伤害已经发生,如一个大型服务被骇,其它服务可以通过验证码等抗脚本方式防止自己受到波及。

但无论如何,从个人角度出发,即使是一个帐号被盗,泄露的个人信息无法挽回,即无法阻止“洗库”。

为什么不能在两个服务上用同一个密码

请勿在两个服务上共用密码。

noarch 特别强调两个是因为说多个可能会让你产生侥幸心理,自作聪明只使用两三个密码;但实际上两个服务共用密码和十个服务共用密码带来的安全隐患是接近的。

上面 noarch 以服务提供商的角度讲解了密码的安全存储。

多数 (noarch 猜测,没有统计) 对安全有一定考量的服务都将密码通过上述加盐 Hash 的方式存储。但即使对数据库中密码的攻击已经被“玩烂了”,攻击它的知识也可以随意获取,依然有服务存侥幸心理,或是 IT 人员技术低下,使用明文存储密码。就像 noarch 所在教育局使用的网课系统一样,如果它被骇,所有北美高中生的个人信息将受到威胁。更恐怖的是,你的老师、学校、政府能随意读取你在那的密码。

如果你还共用密码,那么一个明文存储密码的服务被骇,你的所有帐号将受到立刻、严重的威胁。

但作为用户你能做什么呢?密码的存储方式通常也不被公开,因此你无从知道服务提供商的 IT 人员多么无视安全。你唯一能做的,是隔离这些服务和密码,在每个服务上使用一个不同的密码,避免“一个被骇,全盘被骇”的局面。

noarch 在这里所说的“隔离”仅指密码隔离,并没有涉及到身份隔离。身份隔离则是我们后续在享受自由言论之前:“分裂人格”的魅力中要讲的话题。

你可能会说,这根本不可能!我不可能记住这么多强密码啊!

noarch 没有叫你记住你使用的上千个服务的不同密码。事实上,你只需要记住一两个 - 大多数情况下只有一个 - 密码就行了。

要做到只记一个密码,却能保证所有帐号安全,你需要用到密码管理器。noarch 会在下一篇文章介绍密码管理器如何工作。