有一天 ,面试码时密码密码Joe 发现了一个他常去的什忘送旧论坛书签,但已经有半年没访问了。记密Joe 想看看这个论坛现在有什么变化,只能重置于是面试码时密码密码他进入论坛,输入用户名和密码,什忘送旧却收到密码错误的记密提示 。
几次尝试后 ,只能重置系统提示 Joe 使用“忘记密码”功能。面试码时密码密码于是什忘送旧 Joe 填写了他的邮箱,查收了收件箱中的记密重置密码链接。源码库尽管 Joe 最终通过重新设置的只能重置密码成功登录,但有一个问题让他百思不得其解 :
奇怪,面试码时密码密码为什么我必须重置密码 ?什忘送旧为什么不直接把旧密码发到我的邮箱呢?
很多人可能都有像 Joe 一样的疑问 。发送旧密码不是记密更好吗 ?为什么要强迫我更改密码 ?
这个看似简单的问题实际上涉及到许多信息安全相关的概念 。让我们慢慢寻找问题的答案,并顺便学习一些信息安全的基础知识!
数据库被盗
我们经常会看到新闻报道某个网站的数据再次被盗,免费模板所有客户的个人数据被泄露 ,比如知名域名托管网站 GoDaddy 之前泄露了 120 万用户记录 。
这里我想和大家讨论两个问题:
数据这么容易泄露吗?数据泄露可能会带来什么后果 ?首先来看第一个问题,很多安全漏洞会导致数据泄露 ,而一些攻击这些漏洞的方法比你想象的要简单百倍 。
图片
你想象中的黑客可能像下面这样 ,输入一堆你不知道他们在做什么的命令。屏幕显示出很多黑底白字或绿字的界面,完全看不懂,但他们一操作 ,源码下载网站就被黑了 。
但有些漏洞可能通过在地址栏上改几个字就能成功攻击 ,即使你不懂任何代码。
举个例子 ,假设今天有一个购物网站。买了东西下单后 ,订单确认并重定向到订单页面,页面上有很多你的数据 ,比如姓名、收货地址、联系电话、邮箱等。
然后你发现订单页面的 URL 是:https://shop.example.com/orders?id=14597 。亿华云
巧合的是 ,你的订单号也是 14597 。在好奇心驱使下,你试着把这个数字改成 14596 ,然后按下回车键 。
一些攻击是如此简单和平凡 ,只需更改一个数字,你就可以看到别人的数据 。如果你知道如何编写程序 ,你可以写一个脚本自动获取从 ID 1 到 ID 15000 的高防服务器数据 。然后你就拥有了这个购物网站上所有 15000 个订单的信息——上万客户的个人数据 。
这种漏洞有一个术语 ,叫做 IDOR(Insecure Direct Object References) ,即不安全的直接对象引用。导致这种漏洞的原因是开发时工程师没有注意权限控制 ,允许用户访问其他人的数据。
有些人可能认为我只是为了在本文中说明问题而简化了事情,但现实中的建站模板攻击并不像这个例子这么简单。
这句话只对了一半。大多数网站确实没有这么明显的漏洞,攻击方法也更复杂。然而 ,令人恐惧的是 ,有些网站就是这么简单——改一个数字就能访问别人的数据。
图片
例如,这两个是真实的 IDOR 漏洞:
xarefit 有访问/下载所有会员个人数据的权限。DoorGods 的 IDOR 导致个人数据泄露 。今后,只要你在 URL 栏看到这种数字 ,你可以尝试做一些更改 。即使你不会编写程序 ,也可能发现 IDOR 漏洞 。
个人数据泄露后会怎样 ?
我们已经看到了从防御不力的网站泄露个人数据是多么容易。
那么 ,数据泄露后会对用户产生什么影响呢 ?
最直观的体验应该是诈骗电话,比如某些购书网站或酒店预订网站 。他们打电话给你,声称需要分期退款,并为了获取你的信任,他们甚至可以告诉你你买了哪本书,预订了哪个房间,甚至你的家庭住址和全名。
诈骗团伙能如此清楚地掌握这些信息 ,都是因为数据泄露 。
但除了这些个人数据 ,还有两样东西可能会泄露:你的账号和密码。
你可能会想 :“这只是一个账号和密码,我只要更改该网站的密码然后再用不就行了吗!”
事情可能并没有你想的那么简单。如果你没有使用密码管理软件,我大胆猜测你所有的密码可能都是相同的。因为害怕记不住,人们往往会对所有网站使用相同的密码 。
如果此时你的账号和密码被泄露,黑客能否尝试在其他服务上使用这些凭证呢?
他们可以使用这些凭证登录你的 Google 账户或 Facebook。使用相同密码的人就会被黑。所以虽然最初看起来只是一个购物网站被攻破 ,但其后果可能导致你的 Google 和 Facebook 账户也被黑。
因此,有时某个网站的账户被黑,可能并不是因为该网站存在问题 ,而是黑客在其他地方获取了你的登录信息 ,并尝试在这里使用这些信息而意外成功 。
对于网站开发者来说,保护用户数据至关重要;保护密码也很重要 。有没有好的方法可以保护密码呢?
加密 ?使用某些算法加密密码意味着将加密结果存储在数据库中,因此即使被盗,除非黑客有解密方法 ,否则他们无法轻易访问 。
这听起来像是最安全的方法;然而 ,另一个问题随之而来——开发人员仍然知道如何解密 ,这可能导致工程师滥用他们的访问权限,了解每个用户的实际密码,出售信息或自己利用这些信息。
嗯……似乎我们陷入了困境 ,因为开发人员必须知道数据库中存储的确切密码,对吗 ?否则 ,在登录时如何确认用户名和密码组合是否匹配呢?
此外 ,已经听起来够安全了 ,我们如何使它更安全 ?让网站开发者无法解密或知道我们的实际密码,不是应该足够安全了吗?
答对了 !这正是需要做的 !
没有人知道你的密码 ,包括网站本身
事实上 ,网站的数据库并不存储你的密码。
更准确地说,它不存储你的“原始密码”,而是存储密码经过某种操作后的结果。最重要的是,这种操作是不可逆的。
为了给出一个直接的对比例子,假设今天有一个非常简单的算法可以转换密码。转换方法是:“数字保持不变,英文字母替换为数字(a 变成 1,b 变成 2……z 变成 26)”,以此类推。每个字母被替换为相应的数字 ,不区分大小写(暂时假设没有符号) 。
如果密码是 abc123,转换后变成 123123。
在用户注册期间 ,网站将用户输入的 abc123 转换为 123123,然后将其存储在数据库中。因此 ,数据库中存储的密码是 123123 ,而不是 abc123 。
当用户登录时 ,我们使用相同的逻辑再次转换他们的输入 。如果转换后匹配 ,那么我们不就知道密码是正确的吗?
黑客窃取数据库并获取这组密码 123123 后,他们难道不能推断出它最初是 abc123 吗 ?不 ,不,不——事情没有这么简单 。
123123 ,abcabc,12cab3……这些密码散列后,不还是 123123 吗 ?所以,即使你知道转换规则和结果,也无法将其恢复为“唯一的密码” ,这是这种算法的强大之处 !
这种转换称为散列(hash)。每次 abc123 被散列,结果总是 123123 。但是,从 123123 中 ,你不能确定输入必须是 abc123 ,因为还有其他可能性。
这就是散列与加密的最大区别。
加密和解密是一对;如果某物可以被加密,那么它也可以被解密。因此,如果你知道加密的密文和密钥,你可以确定明文 。但是使用散列,知道散列算法的结果并不能让你反向推理出原始输入是什么。
这种机制的最常见应用之一是安全地存储密码。
在注册期间 ,存储散列密码在数据库中 。登录时,将输入的密码散列并与数据库中存储的散列值进行比较 ,以验证其正确性。即使黑客窃取数据库中的数据,他们也不知道用户的密码,因为他们无法反向推理出原始密码。
这就是为什么当你忘记密码时,网站不会告诉你原始密码 ,因为网站本身也不知道!
所以你不能“找回密码”,只能“重置密码” ,因为重置意味着你输入一个新密码,然后网站将新密码散列并存储在数据库中。以后登录时,它将使用这个新散列值进行比较。
防止预先计算攻击
一些人可能会注意到,这种存储方法似乎有一个漏洞 。继续前面的例子,如果数据库中存储的是 123123 ,但我的原始密码是 abc123 ,那么如果我使用“abcabc” ,散列后也会是 123123 。难道我不能这样登录吗?这似乎不对;这不是我的实际密码。
当两个不同的输入产生相同的输出时,这种情况称为碰撞(hash collision)。碰撞是不可避免的 ,但如果算法设计得好 ,碰撞非常罕见——罕见到几乎可以忽略不计。
前面提到的转换规则只是为了说明问题。实际使用的算法要复杂得多;即使只有一个字母的差异,结果也会大不相同。以 SHA256 为例:
abc123 => 6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090 abc124 => cd7011e7a6b27d44ce22a71a4cdfc2c47d5c67e335319ed7f6ae72cc03d7d63f
相似的输入会产生完全不同的输出 。
前面提到的不安全散列算法的例子应该避免,或者避免自己设计算法。建议使用密码学专家设计的算法,如上面提到的 SHA256 。
使用这些算法时,还应特别注意其安全性 。某些算法虽然由专家设计,但已被证明不安全。例如 ,使用 MD5 存储散列密码被认为是不安全的。
仅存储散列值可以吗?
对不起 ,仅存储密码的散列值是不够的。
为什么呢 ?不是说结果无法逆向推理吗?为什么这还不够?
虽然无法逆向推理结果,但攻击者可以利用“相同输入总是产生相同输出”的特性,预先构建一个包含人们数据的数据库。
例如,假设有一个非常常见的密码“abc123” ,其散列值是“6ca13d”。攻击者可以预先计算并将此关系存储在他们的数据库中 。因此,攻击者的数据库可能包含一百万组最常见的密码,每组都与其对应的散列值配对 。
然后,他们只需在自己的散列数据库中搜索“6ca13d” 。通过查找表,他们可以发现原始密码是“abc123”。这种方法不涉及逆向算法;它只是使用现有数据进行查找。
为了防御这种攻击,还需要做另一件事,叫做加盐(salting)。是的,就像实际的盐一样 。通常 ,为每个用户生成一个唯一的盐——例如 5ab3od(实际上会更长 ,可能是16个或更多字符) 。然后我的密码“abc123”会与我的盐结合,变成“abc1235ab3od” ,然后将其作为散列的输入。
为什么要这样做呢?
因为相比于仅使用“abc123” ,找到“abc1235ab3od”在攻击者的预计算表中可能性显著降低。此外 ,增加长度使暴力破解更加困难 。结果 ,密码变得更难破解。
结语
当你忘记密码时,网站不会将密码发送给你 ,因为即使是网站本身也不知道你的密码。虽然这听起来不太可能 ,但事实确实如此 。出于安全原因 ,这是一个必要的措施。
为了实现这个目标 ,背后最重要的技术原理是散列 。“相同的密码将生成相同的散列值,但从散列值无法反向推理出原始密码”——这就是其中的秘密。
相反 ,如果你发现某个网站可以找回你的密码,那么你应该更加谨慎,因为它可能在其数据库中存储了实际的密码 ,而不是散列值 。在这种情况下 ,如果有一天数据库被黑,账号信息包括密码被黑客窃取,他们可以知道你的实际密码并尝试在其他服务上使用。
关于密码管理 ,现在浏览器也有功能可以自动生成并记住密码 ,或者你可以使用现成的密码管理软件 ,它可以为不同的网站创建不同的密码 。