背景
2011年csdn明文泄密600万用户邮箱和密码出现明文泄露,很多用户对CSDN的明文存储密码的行为表示出愤怒。对于与用户关联的重要数据我们应该要如何加密存储,MD5加密能够满足需求?
要解决这些问题,我们需要引入一个重要的算法-hash算法。
什么是hash算法
Hash,一般翻译做散列、杂凑,或音译为哈希,是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。 引用百度
hash算法特点
- hash算法不能能反向推导出原始数据。
- hahs的冲突概率很小,对于不同的数据,hash出现相同的概率很低。
- hash的计算效率高。
从以上图我们可以看出对于任意相对不那么长的字符串我们始终能够保证我们计算出来的MD5 值都是固定长度的。
应用场景
1.安全加密
常用的加密算法MD5(消息摘要算法)、SHA(安全散列算法)都归属于hash算法。我们如何通过hash算法来实现我们的类似密码存储这种需求呢?
MD5大家很收悉,一个32位长度的MD5存在2^128种组合,所以我们对于要存储的数据(密码),如果通过MD5 32位的算法被破解到的概率是1/2^128。我们看概率被破解到的概率很低,实际理论上还是存在被破解的可能。
但是在实际开发过程中,我们一般都会对于登录有一些限制,例如:连续输N次错误,禁止多长时间不允许在登录。所以在一般情况下,破解类似算法需要花费大量的时间、精力也不一定能够成功。有时候我们没有必要为了概率上的
那么一定特殊情况进行位数增加,比如我们把MD5换成64位的。但是这样会我们就会失去这个算法的高效性,有比如SHA-256比SHA-1安全和复杂,但是他带来计算时间就会长很多很多。
2.文件唯一标识
如果大家有使用过百度网盘,我想大家都对文件秒传有过了解。那他底层是如果做到秒传的呢?我们前面刚才说过,我们可以通过对输入的信息进行MD5计算可以计算出一个md5值,通过这个手段来判断,用户上传的文件MD5值,
是否和服务器存在的文件MD5值是否一样判断是否可以秒传。如果一样直接让用户停止上传,告诉他已经完成传输。不知道大家有没想到这个里面还是存在一些问题的,文件上传时,我们经常上传的是一个比较大的文件,如果我们对
这个大文件进行MD5值计算会非常耗时,甚至电脑卡死的问题。有没什么好方法能够解决?
我们可以对每一个文件采取N等分的方式(大小划分,不需要实际拆分),分别从N等分中取10k加起来计算一个MD5值,从而代替原来整个文件计算MD5值所带来的性能、时间问题。
3.数据校验
BT我们都使用过,我们会先下载一个torrent的种子文件,种子文件是什么东西,里面存储了什么东西。首先我们要了解BT下载时,我们会发现我们下载的文件其实一块一块的文件,他们来源于互联中不同用户的主机。那他是如何保证
来着互联网用户的数据块文件是正确、没有被篡改的呢。其实原理也挺简单的,就是当我们完成一个文件块下载完成时计算整个块的文件hash值,然后和种子文件中的hash值进行对比,判断是否一致,如果一致说明当前块下载成功。如果不一致
从新下载。
4.hashtable hashmap
hashtable hashmap作为程序员都是我们经常使用的类,其实他们底层也都用到了hash算法。数学里鸽巢原理我相信大家都看过,有10只鸽巢,住着11只鸽子。那当中肯定有一个鸽巢里住着两只鸽子。hashtable hashmap我们也可以这么理解他。
大家课可以看以下图:
hashtable hashmap空间都是有限的,所以必定会存在hash冲突的情况,但是我们可以通过链表法解决冲突。
如何解决用户密码安全存储问题
回到我们开篇的问题虽然我们可以通过hash算法 MD5来解决数据安全的问题。大家有咩考虑过一个问题就是如果我们存在一些常用密码例如:00000,123456,654321 这类密码我们要如何保证他不会被暴力破击呢?
因为对于常用密码我们用MD5进行计算时,会发现他计算出来的值是一样的。这样当我们的密文密码泄露出去时,黑客们可以通过密码字典进行常用密码匹配,我相信还会存在很多用户会被盗号的情况。针对这个问题
我们可以引入一个东西叫做盐(salt),把他和用户的密码结合起来一起加密,比如把salt混合到密码里面去,加到头部、加到尾部等等方式,因为盐(salt)泄露的概率较低。这样黑客拿到加密密文想要迅速破解的概率就
较低了。