5

如何安全地保存用户密码

 2 years ago
source link: https://doumao.cc/index.php/%E7%BC%96%E7%A8%8B/%E5%A6%82%E4%BD%95%E5%AE%89%E5%85%A8%E5%9C%B0%E4%BF%9D%E5%AD%98%E7%94%A8%E6%88%B7%E5%AF%86%E7%A0%81.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

也许大家还记得11年csdn的密码泄露事件,csdn使用明文来存储网站600万用户的密码⊙∀⊙!当年我就中招了,而且我基本所有的网站都使用同一个邮箱和同样的密码...

csdn密码泄露事件后,各种大小网站的密码泄露事件层出不穷。在可见的将来,泄露事件仍然会不断出现。

出来工作后,也慢慢地接触了一些安全保存用户的方法。从网站开发者和用户,两种不同的角色角度说下。

网站开发者

明文存储密码

不要使用明文在数据库里存储密码,这是最愚蠢的一种做法。编程初学者很容易就会想到这种“便捷”,他们会想到这种方式编程就简单,而且当用户忘记密码时,进数据库里查看下,就可以告诉用户了。

千万千万不要这要做,我不知道csdn出于什么目的,使用明文存储密码。这样做带来了以下的风险:

  • 所有拥有数据库权限的管理者,都可以登录任何一个用户的账号。
  • 更糟糕的是,我们的密码一般都蕴含着某种规律。例如有人喜欢用名字拼音+生日,而且往往在其他网站也使用相同的密码。

使用对称加密来加密密码

不使用明文,那加密一下就好了,这是一种正常的思维。但有些网站开发者使用对称加密的方法来加密密码,他们把用来加密的密钥,保存在服务器上。他们使用密码来加密,检验用户密码和将数据库里的加密密码解密会明文字符串。

他们使用对称加密的考虑是,他们可以随时更换密钥,来重新生成加密密码。也可以在当前使用的加密算法被破解后,更换更安全的算法。

这样的做法,其实和明文存储没有区别。当你的数据库被脱库后,你的密钥和加密算法往往一起被盗取了。入侵者可以很容易的重新算出用户的明文密码。

某些对称算法可以支持的密码位数也很有限。例如
des只支持56bit,也就是7byte的密码,虽然看起来可支持的密码数量很多,但目前的破解工具可以很容易在一天内生成des加密密码。

同时,相同的密码经过加密后,得到的是相同的加密密码。(这里的加密密码是使用sha256加密得到16进制字符串)

用户名密码加密密码vstorm63451270e36b61dd18c107f86...b8e7f0ca41skyking63451270e36b61dd18c107f86...b8e7f0ca41idealideal199216fe80d03d0c074232d...75c47bcdd5

我们可以很容易知道上面vstorm和ideal使用的是相同的密码。

算法的选择也很重要。某些加密算法,加密密码就泄露了明文密码的某些信息。某些算法,加密密码的字节数,泄露了原来明文密码的字节数。例如明文是7字节,对应的加密密码都是32字节。

所以我们加密要满足下面的要求:

  • 不能从加密密码,解密得到明文密码。
  • 相同的明文密码,不能得到相同的加密密码。
  • 加密密码不能泄露明文密码的信息,例如位数。

使用hash算法(非对称算法)加密

网站开发者应该选择非对称加密,常见的md5,sha1,sha256可以将任意的明文密码,加密得到一个固定位数的加密密码。例如sha256,不论明文密码多少位,加密得到加密密码都是256位。

上面的非对称加密算法,保证了:

  • 不能从加密密码,解密得到明文密码。
  • 不能从加密密码,得到明文密码的位数信息。
  • 任何两个相同的明文密码,很难加密得到相同的加密密码。

上面的算法推荐使用sha256,因为md5和sha1,随着机器性能的不断增长,已经出现了可以从不同的明文密码,得到相同的加密字符串。

简单的python sha256加密代码

import hashlib
def encrypt_password(password:str) -> str:
            m = hashlib.sha256()
            m.update(password.encode())
            return m.hexdigest()

sha256看起来足够满足我们的要求了,但还存在着问题。

  • 相同的明文密码,加密后得到的是相同的加密密码。如果我是用户vstorm,那我知道skyking的密码和我是一样的,都是634512。
  • 而且入侵者,得到加密密码和加密算法后,可以在自己电脑,将明文密码的所有组合,使用加密算法,运算出加密密码。这就是我们常说的“彩虹表”。网络上已经公布了使用明文密码,使用上面常见的加密算法,得到的“彩虹表”。入侵者可以直接下载使用这些“彩虹表”。

“sha256彩虹表”(包含了用户常用的一些密码,如123456,qwert)

加密密码明文密码8d969...c6c921234569e69e...bf37afa80qwert.......

给每个用户的密码加点“盐”

为了对抗“彩虹表”和相同的明文密码得到相同的加密密码,可以给用户的密码“加盐”。
“加盐”,我觉得是一种很贴切的比喻。同样的食材,加不同量的盐,最终的味道就都不一样。用户的明文密码就是食材,加密密码是最后的味道。我们用一个随机的字符串,作为“盐”,它拼接到用户的明文密码前面或者后面,形成新的字符串,将新的字符串传给加密算法。
这样的做法,可以对抗“彩虹表”的攻击,因为网上公布的“彩虹表”都是没有“盐”的,入侵者只能自己“加盐”去生成彩虹表。

同时每个用户加不同的“盐”值,这样即使是相同的明文密码,最终得到的加密密码是不同的。

每个用户加不同“盐”,这样入侵者要针对每个用户生成单独的“彩虹表”,这大大加大了入侵者的运算成本。加相同的“盐”,其实和不加“盐”是一样的,入侵者只需要生成一张“彩虹表”,就可以去破解所有用户的密码。

用户明文密码盐加密密码vstorm634512joiwnuica23089ec52b...d95512492skyking634512vji91ew0f3]df89a9442...27ed86942idealideal19921fsd0923kfdsfb84af467...f85245c8ba

简单的加盐版python sha256加密代码

import hashlib

def encrypt_password(password:str, salt:str) -> str:
        m = hashlib.sha256()
        m.update(password.encode())
        m.update(salt.encode())
        return m.hexdigest()

世界没有觉得安全的系统,请记住这句话。系统总会有被攻破,数据泄露到网络的可能。系统有漏洞,人也有漏洞。
即时网站开发者已经使用非对称加密算法+不同“盐”,很多用户为了方便易记,会使用一些简单的密码,如123456789。入侵者的程序,一般都会先尝试这些简单的密码。
同时,在所有网站都使用同一个密码,也是风险很高的做法。只要有一个网站被攻破,入侵者就可以登入你所有网站的账号。特别是存在csdn这种明文存储密码的网站,入侵者根本就不需要去运算破解密码。
说说我个人一些的做法:

  • 不使用简单有规律的密码,密码的长度要较长,大写字母+小写字母+数字的结合,最好加上特殊字符。
  • 不同网站使用不同的密码。
  • 在一些小网站,如果以后都不会再上,可以使用匿名邮箱去注册账号。
  • 使用lastpassword等密码工具来生成和管理密码。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK