盐(Salt)mysql
在密码学中,是指经过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为“加盐”。算法
以上这句话是维基百科上对于 Salt 的定义,可是仅凭这句话仍是很难理解什么叫 Salt,以及它究竟起到什么做用。sql
早期的软件系统或者互联网应用,数据库中设计用户表的时候,大体是这样的结构:数据库
mysql> desc User; +----------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+-------+ | UserName | varchar(50) | NO | | | | | PassWord | varchar(150) | NO | | | | +----------+--------------+------+-----+---------+-------+
数据存储形式以下:安全
mysql> select * from User; +----------+----------+ | UserName | PassWord | +----------+----------+ | lichao | 123 | | akasuna | 456 | +----------+----------+
主要的关键字段就是这么两个,一个是登录时的用户名,对应的一个密码,并且那个时候的用户名是明文存储的,若是你登录时用户名是 123,那么数据库里存的就是 123。这种设计思路很是简单,可是缺陷也很是明显,数据库一旦泄露,那么全部用户名和密码都会泄露,后果很是严重。参见 《CSDN 详解 600 万用户密码泄露始末》。加密
为了规避第一代密码设计的缺陷,聪明的人在数据库中不在存储明文密码,转而存储加密后的密码,典型的加密算法是 MD5 和 SHA1,其数据表大体是这样设计的:设计
mysql> desc User; +----------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+--------------+------+-----+---------+-------+ | UserName | varchar(50) | NO | | | | | PwdHash | char(32) | NO | | | | +----------+--------------+------+-----+---------+-------+
数据存储形式以下:htm
mysql> select * from User; +----------+----------------------------------+ | UserName | PwdHash | +----------+----------------------------------+ | lichao | 202cb962ac59075b964b07152d234b70 | | akasuna | 250cf8b51c773f3f8dc8b4be867a9a02 | +----------+----------------------------------+
假如你设置的密码是 123,那么数据库中存储的就是 202cb962ac59075b964b07152d234b70 或 40bd001563085fc35165329ea1ff5c5ecbdbbeef。当用户登录的时候,会把用户输入的密码执行 MD5(或者 SHA1)后再和数据库就行对比,判断用户身份是否合法,这种加密算法称为散列。字符串
严格地说,这种算法不能算是加密,由于理论上来讲,它不能被解密。因此即便数据库丢失了,可是因为数据库里的密码都是密文,根本没法判断用户的原始密码,因此后果也不算太严重。get
原本第二代密码设计方法已经很不错了,只要你密码设置得稍微复杂一点,就几乎没有被破解的可能性。可是若是你的密码设置得不够复杂,被破解出来的可能性仍是比较大的。
好事者收集经常使用的密码,而后对他们执行 MD5 或者 SHA1,而后作成一个数据量很是庞大的数据字典,而后对泄露的数据库中的密码就行对比,若是你的原始密码很不幸的被包含在这个数据字典中,那么花不了多长时间就能把你的原始密码匹配出来。这个数据字典很容易收集,CSDN 泄露的那 600w 个密码,就是很好的原始素材。
因而,第三代密码设计方法诞生,用户表中多了一个字段:
mysql> desc User; +----------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+-------+ | UserName | varchar(50) | NO | | | | | Salt | char(50) | NO | | | | | PwdHash | char(32) | NO | | | | +----------+-------------+------+-----+---------+-------+
数据存储形式以下:
mysql> select * from User; +----------+----------------------------+----------------------------------+ | UserName | Salt | PwdHash | +----------+----------------------------+----------------------------------+ | lichao | 1ck12b13k1jmjxrg1h0129h2lj | 6c22ef52be70e11b6f3bcf0f672c96ce | | akasuna | 1h029kh2lj11jmjxrg13k1c12b | 7128f587d88d6686974d6ef57c193628 | +----------+----------------------------+----------------------------------+
Salt 能够是任意字母、数字、或是字母或数字的组合,但必须是随机产生的,每一个用户的 Salt 都不同,用户注册的时候,数据库中存入的不是明文密码,也不是简单的对明文密码进行散列,而是 MD5( 明文密码 + Salt),也就是说:
MD5('123' + '1ck12b13k1jmjxrg1h0129h2lj') = '6c22ef52be70e11b6f3bcf0f672c96ce' MD5('456' + '1h029kh2lj11jmjxrg13k1c12b') = '7128f587d88d6686974d6ef57c193628'
当用户登录的时候,一样用这种算法就行验证。
因为加了 Salt,即使数据库泄露了,可是因为密码都是加了 Salt 以后的散列,坏人们的数据字典已经没法直接匹配,明文密码被破解出来的几率也大大下降。
是否是加了 Salt 以后就绝对安全了呢?淡然没有!坏人们仍是能够他们数据字典中的密码,加上咱们泄露数据库中的 Salt,而后散列,而后再匹配。可是因为咱们的 Salt 是随机产生的,假如咱们的用户数据表中有 30w 条数据,数据字典中有 600w 条数据,坏人们若是想要彻底覆盖的坏,他们加上 Salt 后再散列的数据字典数据量就应该是 300000* 6000000 = 1800000000000,一万八千亿啊,干坏事的成本过高了吧。可是若是只是想破解某个用户的密码的话,只需为这 600w 条数据加上 Salt,而后散列匹配。可见 Salt 虽然大大提升了安全系数,但也并不是绝对安全。
实际项目中,Salt 不必定要加在最前面或最后面,也能够插在中间嘛,也能够分开插入,也能够倒序,程序设计时能够灵活调整,均可以使破解的难度指数级增加。
转自:https://libuchao.com/2013/07/05/password-salt