MD5 (加盐) 加密

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: MD5 (加盐) 加密

刚开始师兄给我说这个东西的时候还以为是什么很高级的东西,结果就是一种加密算法,其原理还是很简单的:

盐(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。这种设计思路非常简单,但是缺陷也非常明显,数据库一旦泄露,那么所有用户名和密码都会泄露,后果非常严重。参见 《CSDN 详解 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,然后做成一个数据量非常庞大的数据字典,然后对泄露的数据库中的密码就行对比,如果你的原始密码很不幸的被包含在这个数据字典中,那么花不了多长时间就能把你的原始密码匹配出来。这个数据字典很容易收集,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 不一定要加在最前面或最后面,也可以插在中间嘛,也可以分开插入,也可以倒序,程序设计时可以灵活调整,都可以使破解的难度指数级增长。

PS,文中所谓第一、二、三代密码的称呼,是我自己 YY 的。

转载自:为什么要在密码里加点“盐”

如果什么事md5的话可以看看imooc的课程:

PHP加密技术专题

1-2 md5信息加密算法 (16:16)

虽然用的是php语言讲解的,但还是十分易懂的

最后附上一段可运行的MD5算法和MD5加盐算法:

public class md5 {
MD5加密算法:
//    public static String getMD5(String str) {
//        try {
//            // 生成一个MD5加密计算摘要
//            MessageDigest md = MessageDigest.getInstance("MD5");
//            // 计算md5函数
//            md.update(str.getBytes());
//            // digest()最后确定返回md5 hash值,返回值为8为字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
//            // BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值
//            return new BigInteger(1, md.digest()).toString(16);
//        } catch (Exception e) {
//            System.out.println("MD5加密出现错误");
//        }
//        return str;
//    }
    public static void main(String[] args) {
        String pwd="password";
        //MD5加盐算法:
        System.out.println(getMD5WithSalt(pwd));
    }
    /**
     * MD5加密工具类
     */
        /**
         * 获取MD5字符串
         */
        public static String getMD5(String content) {
            try {
                MessageDigest digest = MessageDigest.getInstance("MD5");
                digest.update(content.getBytes());
                return getHashString(digest);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
            return null;
        }
        private static final String SALT = "0fdfa5e5a88bebae640a5d88e7c84708";
        /**
         * 获取加盐的MD5字符串
         */
        public static String getMD5WithSalt(String content) {
            return getMD5(getMD5(content) + SALT);
        }
        private static String getHashString(MessageDigest digest) {
            StringBuilder builder = new StringBuilder();
            for (byte b : digest.digest()) {
                builder.append(Integer.toHexString((b >> 4) & 0xf));
                builder.append(Integer.toHexString(b & 0xf));
            }
            return builder.toString();
        }
}


AIEarth是一个由众多领域内专家博主共同打造的学术平台,旨在建设一个拥抱智慧未来的学术殿堂!【平台地址:https://devpress.csdn.net/aiearth】 很高兴认识你!加入我们共同进步!

目录
相关文章
|
4月前
|
存储 NoSQL 数据库
认证服务---整合短信验证码,用户注册和登录 ,密码采用MD5加密存储 【二】
这篇文章讲述了在分布式微服务系统中添加用户注册和登录功能的过程,重点介绍了用户注册时通过远程服务调用第三方服务获取短信验证码、使用Redis进行验证码校验、对密码进行MD5加密后存储到数据库,以及用户登录时的远程服务调用和密码匹配校验的实现细节。
认证服务---整合短信验证码,用户注册和登录 ,密码采用MD5加密存储 【二】
|
3月前
|
数据安全/隐私保护 Python
Python中的MD5加密“解密”
Python中的MD5加密“解密”
67 0
|
2月前
|
存储 Java 数据库
密码专辑:对密码加盐加密,对密码进行md5加密,封装成密码工具类
这篇文章介绍了如何在Java中通过加盐和加密算法(如MD5和SHA)安全地存储密码,并提供了一个密码工具类PasswordUtils和密码编码类PasswordEncoder的实现示例。
51 10
密码专辑:对密码加盐加密,对密码进行md5加密,封装成密码工具类
|
2月前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
39 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
|
2月前
|
数据安全/隐私保护 Python
Python中的MD5加密“解密”
Python中的MD5加密“解密”
108 0
|
2月前
|
IDE 开发工具 数据安全/隐私保护
Python编程实现批量md5加密pdf文件
Python编程实现批量md5加密pdf文件
42 0
|
4月前
|
存储 算法 Java
在Java中使用MD5对用户输入密码进行加密存储、同时登录验证。
这篇文章详细介绍了在Java项目中如何使用MD5算法对用户密码进行加密存储和登录验证,包括加入依赖、编写MD5工具类、注册时的密码加密和登录时的密码验证等步骤,并通过示例代码和数据库存储信息展示了测试效果。
在Java中使用MD5对用户输入密码进行加密存储、同时登录验证。
|
4月前
|
JavaScript 算法 数据安全/隐私保护
烯牛数据JS逆向:MD5数据加密?不存在的!
烯牛数据JS逆向:MD5数据加密?不存在的!
81 1
|
4月前
|
算法 JavaScript 前端开发
消息摘要算法:MD5加密
消息摘要算法:MD5加密
66 1
|
4月前
|
Java C# 数据安全/隐私保护
如何 使 Java、C# md5 加密的值保持一致
如何 使 Java、C# md5 加密的值保持一致
60 0