Java双重MD5加密实现安全登录

 更新时间:2022年7月10日 18:03  点击:529 作者:赵四司机

一:问题引入

今天看到一篇文章说使用MD5对密码进行加密存储也还不能做到很安全,网上有在线解密MD5的网站,我一搜,还真有。接下来我尝试对我存储在数据库中的密码进行解密操作:

fb3013eaa3354b509420113da9d5afe7.png

837987e7457a4e1186c4dcf916dcb66e.png

 可以看到成功将我的密码解密出来,这让我很吃惊,因为我们都知道MD5算法是不可逆的,因为它是其是一种散列函数,使用的是hash算法,在计算过程中原文的部分信息是丢失了的。那么为什么网站中可以将我的密码解密出来呢?

经过一番查找后发现,原来在线解密工具的解密原理很简单,其原理是收集用户常用的简单密码形成了一个密码字典,并将字典中的密码用MD5加密后存储起来,在所谓的“解密“的时候,就将真正用户密码加密都的密文与已存储的密码相比较,如该密文存在于字典当中,即可以“解密”。因此,简单的用MD5对用户密码加密还不安全,我们设置密码时候也通常都会有复杂度检测,比如密码必须带英文数字什么的,就是为了安全性考虑。

知道其解密原理之后,我们尝试一下复杂点的密码看看能不能“解密”出来,首先对密码“qweasd666”进行加密:

5e98f258fa3643fa974ca931577d4e1f.png

 加密之后我们选取32位小写的密文进行解密操作:

b95fa649d9234f839734b42c8fd464ce.png

 可以看到解密失败,说明其原理就是我们上面所说的收集常用的密文进行一一对应。既然解密失败了,那么说明“qweasd666”这个密码是安全的,你们可以都设置这个密码(doge)。

言归正传,说到这个网站成功将我精心设置的密码给破解了,这让我很没有安全感,而且我感觉我很没有面子,我一定要将我的登录安全等级进行提升。

除了上面提到的解密操作之外,还有一个很大的问题就是在前端将数据传输过来时候http采用的是明文传输,如果传输数据包被截取,那么就算你后端的加密算法有多复杂,你的密码也会被别人知道。

二:解决方案

2.1:第一次加密

找到问题所在之后,我们就可以对症下药了,首先我觉得要解决的是http明文传输问题,因为这个风险最大,普通抓包就能抓取密码,这不是很恐怖的一件事吗。解决方案也很简单,既然明文传输不安全,那么我们加密后再进行传输不就行了吗?

我选用的方案仍然还是MD5加密,但是对密码加密前还要加入一个固定salt。salt?是加盐吗,其实差不多,更不如说是加点“佐料”。其基本想法是这样的:当用户首次提供密码时(通常是注册时),由程序往这个密码里撒一些“佐料”,为了减轻开发压力,这个佐料对于每一个用户都是相同的,然后再散列。这样就能防止传输过程中出现明文密码泄露。

2.2:第二次加密

注意上面我提到的是防止出现明文密码泄漏,但是这并不代表密文不会泄漏,假如黑客截取你通过http传输的经过加密后的密码,或者数据库发生泄漏导致加密后的密码被黑客盗取,黑客通过解析前端js文件获得前端固定盐值,那么黑客可能可以通过彩虹表进行反向查询得到原始密码。这时候就二次加密的重要性就出来了,二次加密实现原理为对前端传过来经过加密之后的密码再次和一个随机Salt值结合后进行加密(注意这次是随机的),盐值会在用户登陆的时候随机生成,并存在数据库中。

这时候可能你会和我刚开始一样也会有一个疑惑,那就是你把随机盐值保存到数据库中了,那么如果数据库泄漏那你的随机盐值还有什么作用呢?黑客拿到加密数据进行解密后去除盐值不是就能得到密码了吗?是的,黑客有可能通过这样的手段得到密码,但是前提是他能解密出来,要知道的是MD5是无法直接破解的,只能通过穷举法进行解密。就算黑客拿到了数据库中的加密密码,但是不知道后端的加密过程,他就无法进行解析,就算黑客同时知道加密过程,由于经过了二次加盐二次加密,这时候的密文是很难很难被解析出来的,随着加密数据的复杂度增加,破解成本是呈指数级增加的,在那么大的成本面前相信没有什么黑客愿意去尝试。当然,salt也不一定要加在最前面或最后面,也可以插在中间,也可以分开插入,也可以倒序,程序设计时可以灵活调整,都可以使破解的难度呈指数型增长。

2.3:具体实现

2.3.1:用户注册

  • 前端对用户输入的密码进行md5加密(固定的salt)
  • 将加密后的密码传递到后端
  • 后端随机生成一个salt
  • 使用生成salt对前端传过来的密码进行加密,然后将加密后密码和salt一起保存到db中

2.3.2:用户登录

  • 前端对用户输入的密码进行md5加密(固定的salt)
  • 将加密后的密码传递到后端
  • 后端使用用户账号取出用户信息
  • 后端对加密后的密码在进行md5加密(取出盐),然后与数据库中存储的密码进行对比
  • 匹配则登录成功,否则登录失败

三:代码实现

3.1:第一次加密

3.1.1:前端

const params = {
    ...this.ruleForm,
    sex: this.ruleForm.sex === '女' ? '0' : '1',
    //设置密码加密(加上固定salt值)
    password: md5(this.ruleForm.password + this.salt)
}
addEmployee(params).then(res => {
    if (res.code === 1) {
        this.$message.success('员工添加成功!')
        if (!st) {
            this.goBack()
        } else {
            this.ruleForm = {
                username: '',
                'name': '',
                'phone': '',
                password: '',
                // 'rePassword': '',/
                'sex': '男',
                'idNumber': ''
            }
        }
    } else {
        this.$message.error(res.msg || '操作失败')
    }
}

3.1.2:后端

/**
* 添加员工
*/
@PostMapping
public R<String> save(@RequestBody Employee employee){
    //生成随机salt值
    String salt = RandomStringUtils.randomAlphanumeric(5);
    //设置随机盐值
    employee.setSalt(salt);
    //设置密码二次加密
    employee.setPassword(DigestUtils.md5DigestAsHex((salt + employee.getPassword()).getBytes()));
 
    boolean save = employeeService.save(employee);
    if(save){
        return R.success("添加成功!");
    }
    return R.error("添加失败!");
}

3.2:第二次加密

3.2.1:前端

const params = {
    ...this.loginForm,
    //登录密码加上固定盐值后发送
    password: md5(this.loginForm.password + this.salt),
}
let res = await loginApi(params)
if (String(res.code) === '1') {
    localStorage.setItem('userInfo', JSON.stringify(res.data))
    window.location.href = '/backend/index.html'
} else {
    this.$message.error(res.msg)
    this.loading = false
}

3.2.2:后端

/**
 * 员工登录
 */
@PostMapping("/login")
public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee){
    //1.获取传输过来的加密后的密码值
    String encryPassword = employee.getPassword();
 
    //2.从数据库中获取用户信息
    LambdaQueryWrapper<Employee> lqw = new LambdaQueryWrapper<>();
    lqw.eq(Employee::getUsername,employee.getUsername());
    Employee emp = employeeService.getOne(lqw);
 
    //3.如果没有查询到则返回登陆失败查询结果
    if(emp == null){
        return R.error("没有查询到该用户信息!");
    }
 
    //4.获取注册时保存的随机盐值
    String salt = emp.getSalt();
 
    //5.将页面提交的密码password进行md5二次加密
    String password = DigestUtils.md5DigestAsHex((salt + encryPassword).getBytes());
 
    //6.密码比对,如果不一致则返回登陆失败结果
    if(!emp.getPassword().equals(password)){
        return R.error("密码错误!");
    }
 
    //7.查看员工状态是否可用
    if(emp.getStatus() == 0){
        return R.error("该员工已被禁用!");
    }
    
    //8.登录成功,将员工id存入Session对象并返回登录成功结果
    request.getSession().setAttribute("employee",emp.getId());
    return R.success(emp);
}

到此这篇关于Java双重MD5加密实现安全登录的文章就介绍到这了,更多相关Java双重MD5加密 内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

原文出处:https://blog.csdn.net/weixin_45750572/article/details/125609

[!--infotagslink--]

相关文章

  • Java实现经典游戏复杂迷宫

    这篇文章主要介绍了如何利用java语言实现经典《复杂迷宫》游戏,文中采用了swing技术进行了界面化处理,感兴趣的小伙伴可以动手试一试...2022-02-01
  • java 运行报错has been compiled by a more recent version of the Java Runtime

    java 运行报错has been compiled by a more recent version of the Java Runtime (class file version 54.0)...2021-04-01
  • 在java中获取List集合中最大的日期时间操作

    这篇文章主要介绍了在java中获取List集合中最大的日期时间操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
  • 图解PHP使用Zend Guard 6.0加密方法教程

    有时为了网站安全和版权问题,会对自己写的php源码进行加密,在php加密技术上最常用的是zend公司的zend guard 加密软件,现在我们来图文讲解一下。 下面就简单说说如何...2016-11-25
  • 教你怎么用Java获取国家法定节假日

    这篇文章主要介绍了教你怎么用Java获取国家法定节假日,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下...2021-04-23
  • Java如何发起http请求的实现(GET/POST)

    这篇文章主要介绍了Java如何发起http请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
  • 浅谈Java与C#的一些细微差别

    说起C#和Java这两门语言(语法,数据类型 等),个人以为,大概有90%以上的相似,甚至可以认为几乎一样。但是在工作中,我也发现了一些细微的差别...2020-06-25
  • 解决Java处理HTTP请求超时的问题

    这篇文章主要介绍了解决Java处理HTTP请求超时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29
  • java 判断两个时间段是否重叠的案例

    这篇文章主要介绍了java 判断两个时间段是否重叠的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
  • vue接口请求加密实例

    这篇文章主要介绍了vue接口请求加密实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-12
  • 超简洁java实现双色球若干注随机号码生成(实例代码)

    这篇文章主要介绍了超简洁java实现双色球若干注随机号码生成(实例代码),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-02
  • Java生成随机姓名、性别和年龄的实现示例

    这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
  • java 画pdf用itext调整表格宽度、自定义各个列宽的方法

    这篇文章主要介绍了java 画pdf用itext调整表格宽度、自定义各个列宽的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31
  • AES加密解密的例子小结

    关于AES加密的算法我们就不说了,这里主要给各位演示了三个关于AES算法实现的加密例子,希望本文章能给你带来帮助。 话不多说,先放上代码,一共有两个文件:AES.php(aes算...2016-11-25
  • java正则表达式判断前端参数修改表中另一个字段的值

    这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
  • Java使用ScriptEngine动态执行代码(附Java几种动态执行代码比较)

    这篇文章主要介绍了Java使用ScriptEngine动态执行代码,并且分享Java几种动态执行代码比较,需要的朋友可以参考下...2021-04-15
  • node.JS md5加密中文与php结果不一致怎么办

    这次文章要给大家介绍的是node.JS md5加密中文与php结果不一致怎么办,不知道具体解决办法的下面跟小编一起来看看。 因项目需要,需要Node.js与PHP做接口调用,发现nod...2017-07-06
  • Java开发实现人机猜拳游戏

    这篇文章主要介绍了Java开发实现人机猜拳游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-03
  • Java List集合返回值去掉中括号('[ ]')的操作

    这篇文章主要介绍了Java List集合返回值去掉中括号('[ ]')的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-29
  • NODE.JS加密模块CRYPTO常用方法介绍

    使用require('crypto')调用加密模块。加密模块需要底层系统提供OpenSSL的支持。它提供了一种安全凭证的封装方式,可以用于HTTPS安全网络以及普通HTTP连接。该模块还提供了一套针对OpenSSL的hash(哈希),hmac(密钥哈希),cipher...2014-06-07