加密

本文探讨了密码安全的不同阶段,介绍了如何通过在密码中加入随机字符串(盐)来增加密码的安全性,防止密码被轻易破解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么要在密码里加点

盐(Salt)

在密码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为加盐

以上这句话是维基百科上对于 Salt 的定义,但是仅凭这句话还是很难理解什么叫 Salt,以及它究竟起到什么作用。

第一代密码

早期的软件系统或者互联网应用,数据库中设计用户表的时候,大致是这样的结构:

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。这种设计思路非常简单,但是缺陷也非常明显,数据库一旦泄露,那么所有用户名和密码都会泄露,后果非常严重。参见优快云 详解 600 万用户密码泄露始末》

第二代密码

为了规避第一代密码设计的缺陷,聪明的人在数据库中不在存储明文密码,转而存储加密后的密码,典型的加密算法 MD5 和 SHA1,其数据表大致是这样设计的:

mysql> desc User;

+----------+--------------+------+-----+---------+-------+

| Field    | Type         | Null | Key | Default | Extra |

+----------+--------------+------+-----+---------+-------+

| UserName | varchar(50)  | NO   |     |         |       |

| PwdHash  | char(32)     | NO   |     |         |       |

+----------+--------------+------+-----+---------+-------+

数据存储形式如下:

mysql> select * from User;

+----------+----------------------------------+

| UserName | PwdHash                          |

+----------+----------------------------------+

| lichao   | 202cb962ac59075b964b07152d234b70 |

| akasuna  | 250cf8b51c773f3f8dc8b4be867a9a02 |

+----------+----------------------------------+

假如你设置的密码是 123,那么数据库中存储的就是 202cb962ac59075b964b07152d234b70 或 40bd001563085fc35165329ea1ff5c5ecbdbbeef。当用户登陆的时候,会把用户输入的密码执行 MD5(或者 SHA1)后再和数据库就行对比,判断用户身份是否合法,这种加密算法称为散列

严格地说,这种算法不能算是加密,因为理论上来说,它不能被解密。所以即使数据库丢失了,但是由于数据库里的密码都是密文,根本无法判断用户的原始密码,所以后果也不算太严重。

第三代密码

本来第二代密码设计方法已经很不错了,只要你密码设置得稍微复杂一点,就几乎没有被破解的可能性。但是如果你的密码设置得不够复杂,被破解出来的可能性还是比较大的。

好事者收集常用的密码,然后对他们执行 MD5 或者 SHA1,然后做成一个数据量非常庞大的数据字典,然后对泄露的数据库中的密码就行对比,如果你的原始密码很不幸的被包含在这个数据字典中,那么花不了多 长时间就能把你的原始密码匹配出来。这个数据字典很容易收集,优快云 泄露的那 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 不一定要加在最前面或最后面,也可以插在中间嘛,也可以分开插入,也可以倒序,程序设计时可以灵活调整,都可以使破解的难度指数级增长。

=====================================================================

散列算法(Hash Function)中,最为常用的是MD5(Message-Digest Algorithm 5)算法MD5是一个较为古老的算法,一度被广泛应用于安全领域。比如在UNIX系统中用户的密码就是以MD5(或其它类似的算法)经加密后存储在文件 系统中。当用户登录的时候,系统把用户输入的密码计算成MD5值,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。

不过,由于MD5的弱点被不断发现以及计算机能力不断的提升,通过碰撞的方法有可能构造两个具有相同MD5的信息,使MD5算法在目前的安全环境下有一点 落伍。从实践角度,不同信息具有相同MD5的可能性还是非常低的,通常认为是不可能的,通过碰撞的方法也很难碰撞出复杂信息的MD5数值。

因此,MD5算法还是被广泛的用作检验文件是否变化的散列函数,很多类似迅雷、旋风这样的下载工具,都可以通过MD5来验证,用户下载下来的文件是否被修改。

代码如下:

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.math.BigInteger;

import java.nio.MappedByteBuffer;

import java.nio.channels.FileChannel;

import java.security.MessageDigest;

public class Password {

 public static String getMd5ByFile(File file) throws FileNotFoundException {

        String value = null;

        FileInputStream in = new FileInputStream(file);

        //MD5验证文件一致性

try {

    MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());

    MessageDigest md5 = MessageDigest.getInstance("MD5");

    md5.update(byteBuffer);

    BigInteger bi = new BigInteger(1, md5.digest());

    value = bi.toString(16);

} catch (Exception e) {

    e.printStackTrace();

} finally {

        if(null != in) {

        try {

        in.close();

    } catch (IOException e) {

        e.printStackTrace();

    }

    }

}

return value;

}

public static void main(String[] args) throws IOException {

String path="E:\\aaaaa.txt";

String path2="E:\\svn_site-1.8.8 - 副本.zip";

String v = getMd5ByFile(new File(path));

String v2 = getMd5ByFile(new File(path2));

System.out.println("MD5:"+v);

System.out.println("MD5:"+v2);

}

}

 

在用户密码的处理方面,MD5总的来看还算是安全的,至少比明文保存密码要好的多,目前破解MD5主要依靠大型字典的方法,将常用密码进行MD5后建立数 据库,然后和MD5数值进行对比,通过这样的方法来“破解”MD5,因此,通常直接将密码进行MD5处理的话,一些弱密码很容易可以通过这种手段“破解” 出来。

不过,如果在散列的过程中,加入足够长的salt(即干扰字符串),并且salt加入一些动态信息,例如username、随机码等,这样生成的MD5还 是很难被破解的,因为仅仅从数据库无法看到MD5具体的处理过程,必须同时看到处理时的源代码才可以,这就给破解MD5带来相当大的难度。

还有一个方法,既然简单密码的MD5是不安全的,网站的开发者只需要一个简单的技巧就能提高密码的安全度:在用户注册的时候,录入新密码后进行判断,强制密码必须8位以上,并包含字母和数字,否则不让注册,这样用户注册后使用的密码就都是不容易被破解的密码了。

如果需要更安全的算法,建议不用MD5,而使用SHA-256SHA(Secure Hash Algorithm,安全散列算法)是美国国家安全局(NSA)设计,美国国家标准与技术研究院(NIST)发布的一系列密码散列函数。目前还没有出现针 对SHA-256算法的有效碰撞攻击方法,该算法也是开源算法,在很多地方可以找到,是MD5的一个不错的后继者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值