关于 md5 密码加密的一点小疑问

2016-08-22 14:43:50 +08:00
 binbinyouliiii

    现在很多公司都用 md5 加密来加密密码,我们公司也是用的这个方式(不是我写的),众所周知, md5 是不可逆的,所以存在数据库的密码是加密的,如果用户从前台传来密码,按照我现在所知的应该只能从传来的密码再加密后和数据库进行比较。
    前几天又看到有一个叫彩虹表的东西,觉得跟字典差不多,那这样岂不是很不安全,既然 md5 不可逆,那为什么公司都不自己随便创个加密方式,非要用 md5 ,有了彩虹表这个东西, md5 又比普通的加密安全吗?


刚实习的新手,有小白的地方轻喷😃

13349 次点击
所在节点    Java
105 条回复
binbinyouliiii
2016-08-22 19:52:08 +08:00
@damean 大神,这么厉害,“ Java 这么简单”
话说 v 友们都对 java 很排斥吗
damean
2016-08-22 19:56:36 +08:00
@binbinyouliiii java 真算是简单的。
但是“排斥”是什么鬼?你是怎么脑补出“排斥”的?“简单”==“排斥”?
binbinyouliiii
2016-08-22 20:00:35 +08:00
@damean 不是,我之前再 v 站看过几篇帖子,很多人对 java 都以嘲笑的态度来说的
maxsec
2016-08-22 20:47:49 +08:00
"0e31a" == 0
"0e1ba" == 0

"0e31a" =? "0e1ba"
nvidiaAMD980X
2016-08-22 21:58:28 +08:00
直接上 SHA512
ZE3kr
2016-08-22 22:14:25 +08:00
你说的应该是如何存储密码以达到验证用户登录,而不是密码加密

最不安全的是密码存明文,一般情况下没事,但一旦数据库被拖库,然后所有用户的密码都被知道。

所以使用正确的方式存储密码可以尽量减少上述情况带来的灾难。

首先,不应该使用 SHA-0 ( md5 ), SHA-0 的位数太短,已经不安全, SHA-1 目前都被认为不足够安全了,所以应该使用 SHA-256 或更高位数的, SHA-512 感觉没必要。

应该这样存储,用户一个表中,应该包含这两样,都要存储

salt = rand() # 一个随机数,位数最好要长于 256 个比特
password = hash( password + salt )

这样在验证用户的时候,读取这两个字段验证:

if( hash( password + salt ) == hash( input_password + salt ) ){
// 登录成功
}


关于已知数据库后破解原密码难度(假设 hash 算法达到了 hash 算法应该达到的安全性):

1 只存储 hash :

直接使用当前算法的彩虹表,(几乎)可以破解所有用户的原密码

2 存储加一样的盐的 hash :

可以针对当前的盐重新生成彩虹表,然后就能破解所有用户的原密码,难度远大于前者

3 存储一个随机的盐和加随机的盐的 hash :

必须针对每个用户单独破解,破解难度所有用户原密码难度直升至(基本上)不可能,难度远大于前者
ZE3kr
2016-08-22 22:20:52 +08:00
随手创个加密方式?不是不可以,但是绝对不要这样做!

目前使用的加密方法都是经过大量的实际使用而确认这是个“好”的加密算法

几乎没有人会随手创个“好”的加密方式,如果你学过密码学,一些加密函数的实现,那么就再也不会想要自己创加密方式了。
bombless
2016-08-22 22:27:31 +08:00
一般不用 md5 都用 sha 并加盐了,不开玩笑

哈希算法未必能散列的很好,谨慎一点好
edsgerlin
2016-08-22 22:35:54 +08:00
md5 都是什么年代的玩意儿了,也就在不重视用户信息安全的中国大陆开发者里头算是自以为比明文存储强一些的 Best Practice 。
单纯的 hash function 就算是 SHA3-512 也不应该作为 KDF 使用,即使加 nonce as salt 也不安全,这应该是普通开发者应该有的常识。说什么 MD5 不够安全应该用 SHA 系列的也只是五十步笑百步而已。
安全界现在的共识是在 GPGPU 时代连 PBKDF2 、 bcrypt 这种都不能视为安全的 KDF 。当前得到较广泛使用的 GPGPU-proof 的方案是 scrypt ,然而依然有 ASIC 可以搞它。
目前最安全的方案应该是 Argon2 ,只是对它的 Cryptanalysis 还不够多,不建议在生产系统中用。
简单的说:
安全性&计算开销: Argon2 > scrypt > bcrypt > PBKDF2 > hash with salt > plain hash > plaintext
没有历史包袱的新系统最低限度应该用 PBKDF2 , cost factor 还要设得尽量大些反 rainbow table 。如果能用 scrypt 尽量上 scrypt 。
认为普通 hash function 就能当 KDF 用的都应该去补习一下密码学导论,而直接把用户明文密码存储入库的蠢货应该枪毙。
edsgerlin
2016-08-22 22:40:38 +08:00
楼上那些说应该用 SHA 系取代 MD5 来提高安全性的,如果用户密码不是随机生成的话,拖了库,常见的 12 位以内密码用 GPU 算分分钟出个 rainbow table 。
假如用户密码都是用 LastPass 等生成的 48 字符以上的随机字符串的话用 hash function 做 KDF 倒是足够安全,然而现实并没有那么简单。
如果你们真有心提高用户密码存储的安全系数还是去补补密码学基础吧……
edsgerlin
2016-08-22 22:42:55 +08:00
有兴趣可以参考 OWASP 上的相关资料,码农在信息安全方面知道这些基本上是够用了。
https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet
https://www.owasp.org/index.php/Hashing_Java
mingyun
2016-08-22 22:52:57 +08:00
bcypt+1
mikicomo
2016-08-22 23:55:49 +08:00
@damean 好多人只是吐槽 JAVA 的语法吧...其实呢...我觉得 JAVA7/8 很不错啊,没那么多值得吐槽的吧....可是 V2 是 pythoner 的社区, java 被吐槽两句也是正常嘛,毕竟和 python 比起来不简洁是真的....可是谁也不能排斥 java 不是, N 多大型系统都是 java 带起来的呐,你看 BAT 哪家不需要 java ,只是 java 年纪大了嘛,被吐槽是正常哒
msg7086
2016-08-23 08:18:29 +08:00
@edsgerlin Overkill 了。无脚大楼可能会用那个级别,普通的网站真没必要。加了随机盐的 MD5 已经可以挡住普通破解者了,如果他们没有西湖之光的话。
firebroo
2016-08-23 08:21:30 +08:00
如果为了保护用户密码 md5 加随机不固定长度 salt 足够安全了,至于两次 md5 自然是没有必要,仅仅只是让对方生成长虹表的时间*2 而已。 md5 最初的设计就不是用来加密的。自创算法是没有数学理论支撑,算法公开就完。
Clarencep
2016-08-23 09:10:33 +08:00
@ostholz @mingyun bcrypt -1

用户的密码不应该使用 bcrypt 这样可以解密的加密方式 -- 除了用户之外的所有人都不应该知道用户的密码。
用户密码的存放肯定以及必须使用单向加密的方式,也就是用 hash 算法,而不是用 bcrypt 这样的可以解密的加密方式。
annielong
2016-08-23 10:00:12 +08:00
对于一般网站,对 md5 进行简单的变形或者增减就够了,
glasslion
2016-08-23 10:07:26 +08:00
@msg7086 bubcrypt 本来就是哈希算法
kaneyuki
2016-08-23 10:41:16 +08:00
于是加盐的根本目的是把被加密数据变长,让彩虹表生成变得极为困难咯?
edsgerlin
2016-08-23 10:41:40 +08:00
@msg7086 即使是随机盐,要知道大部分用户的密码都不是随机生成而是有一定规律的,比如日期、手机号、身份证号等以及一些拼音、英文单词的组合等,因此可以说 95%以上用户的密码的信息熵都可以说是达不到 48bit 以上的。如果针对特定用户进行 targeted attack ,用 CUDA 推算原密码是分分钟的事情。因此必须用比通用 hash function 计算开销高得多的 key derivation function 才能保障安全。

@Clarencep 多看看书, bcrypt 不可逆,而且 bcrypt 是专用 KDF ,做密码变换比 MD5 之类的通用 hash 好多了。

说二次 Hash 就很安全的也是 Naive ,要知道 PBKDF2 就是标准化的 N 次通用 hash 迭代。例如 Wi-Fi 加密常用的 WPA2-PSK 是用 4096 次 SHA1-HMAC 迭代来生成 256bit 的 AES 密钥, salt 用的是 SSID 。

在不能确保用户使用信息熵足够多的密码的情况下采用单纯的 hash with nonce as salt 都是不安全的,而唯一能确保用户使用信息熵足够多的密码的方法是鼓励用户用 LastPass 、 KeePass 、 1Password 之类的密码管理器生成 48 字符以上随机字串做密码(单 ASCII 字符信息熵可以认为是 6bit 吧,这里假设要提供约 256bit 强度的信息熵),而且一站一密。这个条件明显比用 bcrypt 保护用户愚蠢的密码更不切实际。

现代 KDF 的发展史就是提高计算复杂度(PBKDF2, bcrypt)->提高空间复杂度(scrypt)->提高 ASIC 实现复杂度(Argon2),一切都是为了保护用户愚蠢的低熵密码。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/300946

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX