写在前面

在上一篇文章《Shiro入门学习---使用自定义Realm完成认证|练气中期》当中,我们学会了使用自定义Realm实现shiro数据源的切换,我们可以切换成从关系数据库如MySQL中读取用户认证信息进行认证,亦可从非关系型数据库例如mongodb中读取用户认证信息进行认证。这是一个伟大的进度,这使得我们可以使用shiro来提升我们应用程序的安全度了,

那么,请大家思考一个问题,我们的应用程序真的安全了吗?

我把咱么上一篇文章当中的认证方法代码摘抄在下面给大家看看

  1. /**认证
  2. * @author 赖柄沣 bingfengdev@aliyun.com
  3. * @date 2020-10-04 11:01:50
  4. * @param authenticationToken
  5. * @return org.apache.shiro.authz.AuthorizationInfo
  6. * @throws AuthenticationException
  7. * @version 1.0
  8. */
  9. @Override
  10. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
  11. // 1. 从token中获取用户名
  12. String principal = (String) authenticationToken.getPrincipal();
  13. //2. 根据用户名查询数据库并封装成authenticationinfo对象返回(模拟)
  14. if (principal == "xiangbei") {
  15. AuthenticationInfo authInfo = new SimpleAuthenticationInfo("xiangbei","123",this.getName());
  16. return authInfo;
  17. }
  18. return null;
  19. }

在16行当中,我们模拟从数据库当中查询出了用户的注册信息,包括账户和密码,并且这里的密码是明文的。这意味着如果我们的用户密码被泄露了(这里用户原因导致的泄露除外),那么一些不友好的朋友将可以随意的进出我们的系统。这不但让我们的应用程序变得不安全,而且还会让我们面临法律风险。

以下内容摘自《网络安全法》

第三十四条 网络运营者应当建立健全用户信息保护制 度,加强对用户个人信息、隐私和商业秘密的保护

第三十五条 网络运营者收集、使用公民个人信息,应当 遵循合法、正当、必要的原则,明示收集、使用信息的目 的、方式和范围,并经被收集者同意。 网络运营者不得收集与其提供的服务无关的公民个人 信息,不得违反法律、行政法规的规定和双方的约定收 集、使用公民个人信息,并应当依照法律、行政法规的规 定或者与用户的约定,处理其保存的公民个人信息。 网络运营者收集、使用公民个人信息,应当公开其收 集、使用规则。

第三十六条 网络运营者对其收集的公民个人信息必须严 格保密,不得泄露、篡改、毁损,不得出售或者非法向他 人提供。 网络运营者应当采取技术措施和其他必要措施,确保 公民个人信息安全,防止其收集的公民个人信息泄露、毁 损、丢失。在发生或者可能发生信息泄露、毁损、丢失的 情况时,应当立即采取补救措施,告知可能受到影响的用 户,并按照规定向有关主管部门报告。

所以,我们需要对用户信息进行加密保护。对于账户密码信息,我们应该采取不可逆的加密方式。也就是说,我们对密码进行加密存储后,哪怕其获取了我们的密文,他也不能得到我们的密码明文。这样就对我们的用户信息起到了一个很好的保护作用。

MD5加密算法和salt盐值加密

MD5加密算法

什么是MD5加密

MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。

特点

  1. 不可逆,也就是说其本身上不能由密文推出明文,

    但是,如果明文比较简单常见,还是存在泄露风险,例如先生成好简单明文的密文,然后使用穷举法进行破解;

  2. 对于同一个明文,无论加密多少次其密文都是一样的;

  3. 生成的结果始终是一个16进制的32位字符串。

作用

  1. 数字签名(校验和)

    例如对于一份文件,为了保证网络传输当中不发生改变,我提前对其用md5加密算法进行加密,得到一段密文。我将这份文件和密文分别发给你。你在收到文件后也对其使用md5加密一次,得到一个密文。这时,你就可以比较两个密文是否一致,如果一致,则文件没有被篡改,反之,文件已经被篡改。

  2. 加密

  3. 垃圾邮件筛选

    原理和作用1一样

salt盐值加密策略

在上面的介绍md5加密算法时我们讲到,虽然MD5算法本身不可逆,但是如果用户采用简单的字符串作为密码的话,仍然有被暴力破解的风险。因此,为了解决这个问题,我们需要在对密码加密之前使其变得复杂化。

而加盐就是其中的一种方式。所谓的加盐就是在原密码的基础上,加上一段随机字符串。然后再加密。

当然,如果盐值随着密码一起被泄露出去,也是存在着密码被破解的风险的,我们只能做到相对安全。

为了增加破解难度,可以在加盐时采取一定的策略,例如哈希加盐、加密后多次哈希。

当然,这要在安全跟性能直接做个平衡。

shiro使用MD5+salt加密

分析

在进行编码之前,我们需要理一下流程:

  1. 用户注册或系统分配账户时,服务层在接收到账号和凭证信息后,先对凭证信息采用md5+salt进行加密处理,然后将账号、加密后的密码还有盐值存入数据库;

  2. 用户登录请求接收后,先根据请求中的账号查询数据库:

    2.1 如果没有查到,直接返回“用户名或密码错误”的类似提示

    2.2 如果查到了账户信息,就执行步骤3;

  3. 将账号和加盐后凭证封装成AuthenticationInfo对象返回给shiro,shiro执行步骤4

  4. 对请求中的凭证进行加盐处理并执行步骤5

  5. 对加盐后的凭证进行md5加密,并将密文跟数据库当中的存储的密文进行比对:

    5.1 如果匹配成功,则认证通过

    5.2 如果匹配失败,则返回“用户名或密码错误”的类似提示

实现

编写自定义Realm并切换掉默认的凭证匹配器

  1. /**自定义Realm对象
  2. * @author 赖柄沣 bingfengdev@aliyun.com
  3. * @version 1.0
  4. * @date 2020/10/4 11:00
  5. */
  6. public class MySqlRealm extends AuthorizingRealm {
  7. public MySqlRealm() {
  8. //设置凭证匹配器,修改为hash凭证匹配器
  9. HashedCredentialsMatcher myCredentialsMatcher = new HashedCredentialsMatcher();
  10. //设置算法
  11. myCredentialsMatcher.setHashAlgorithmName("md5");
  12. //散列次数
  13. myCredentialsMatcher.setHashIterations(1024);
  14. this.setCredentialsMatcher(myCredentialsMatcher);
  15. }
  16. /**授权
  17. * @author 赖柄沣 bingfengdev@aliyun.com
  18. * @date 2020-10-04 11:01:50
  19. * @param principalCollection
  20. * @return org.apache.shiro.authz.AuthorizationInfo
  21. * @throws AuthenticationException
  22. * @version 1.0
  23. */
  24. @Override
  25. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
  26. return null;
  27. }
  28. /**认证
  29. * @author 赖柄沣 bingfengdev@aliyun.com
  30. * @date 2020-10-04 11:01:50
  31. * @param authenticationToken
  32. * @return org.apache.shiro.authz.AuthorizationInfo
  33. * @throws AuthenticationException
  34. * @version 1.0
  35. */
  36. @Override
  37. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
  38. // 1. 从token中获取用户名
  39. String principal = (String) authenticationToken.getPrincipal();
  40. //2. 根据用户名查询数据库并封装成authenticationinfo对象返回(模拟)
  41. if (principal == "xiangbei") {
  42. //四个参数分别是数据库中的账号、加密后的密码、盐值、realm名字
  43. AuthenticationInfo authInfo = new SimpleAuthenticationInfo("xiangbei",
  44. "ff595c47b51b4cf70fddce090f68879e",
  45. ByteSource.Util.bytes("ee575f62-0dda-44f2-b75e-4efef795018f"),
  46. this.getName());
  47. return authInfo;
  48. }
  49. return null;
  50. }
  51. }

编写认证器

  1. /**认证管理器
  2. * @author 赖柄沣 bingfengdev@aliyun.com
  3. * @version 1.0
  4. * @date 2020/10/4 11:11
  5. */
  6. public class CurrentSystemAuthenticator {
  7. private DefaultSecurityManager securityManager;
  8. public CurrentSystemAuthenticator() {
  9. //创建安全管理器
  10. securityManager = new DefaultSecurityManager();
  11. //设置自定义realm
  12. this.securityManager.setRealm(new MySqlRealm());
  13. //将安全管理器设置到安全工具类中
  14. SecurityUtils.setSecurityManager(securityManager);
  15. }
  16. public void authenticate(String username,String password) {
  17. //获取当前登录主题
  18. Subject subject = SecurityUtils.getSubject();
  19. //生成toeken
  20. UsernamePasswordToken token = new UsernamePasswordToken(username, password);
  21. //进行认证
  22. try {
  23. subject.login(token);
  24. }catch (UnknownAccountException | IncorrectCredentialsException e) {
  25. System.out.println("用户名或密码不正确");
  26. }
  27. //打印认证状态
  28. if (subject.isAuthenticated()){
  29. System.out.println(token.getPrincipal()+" 认证通过!");
  30. }else {
  31. System.out.println(token.getPrincipal()+" 认证未通过!");
  32. }
  33. }
  34. }

测试

生成加密后的密码
  1. /**
  2. * @author 赖柄沣 bingfengdev@aliyun.com
  3. * @version 1.0
  4. * @date 2020/10/4 21:37
  5. */
  6. public class Md5Test {
  7. @Test
  8. public void testMd5(){
  9. //三个参数分别对应密码明文、盐值、散列次数
  10. String salt = UUID.randomUUID().toString();
  11. Md5Hash md5Hash = new Md5Hash("123", salt,1024);
  12. System.out.println("密文:"+md5Hash.toHex());
  13. System.out.println("盐值:"+salt);
  14. }
  15. }

输出

  1. 密文:ff595c47b51b4cf70fddce090f68879e
  2. 盐值:ee575f62-0dda-44f2-b75e-4efef795018f
进行认证测试
  1. /**
  2. * @author 赖柄沣 bingfengdev@aliyun.com
  3. * @version 1.0
  4. * @date 2020/10/4 11:20
  5. */
  6. public class AuthcTest {
  7. private CurrentSystemAuthenticator authenticator;
  8. @Before
  9. public void init() {
  10. this.authenticator = new CurrentSystemAuthenticator();
  11. }
  12. @Test
  13. public void testAuthc(){
  14. this.authenticator.authenticate("xiangbei","123");
  15. }
  16. }

输出

  1. xiangbei 认证通过!

写在最后

在这篇文章当中,我们主要是简单了解了shiro中的加密策略以及如何使用MD5+salt对密码进行加密。大家可以尝试着将MD5换成SHA-256加密算法再测一下。

在下一篇文章当中,作者将介绍SpringBoot整合Shiro的相关内容,文章可能有点长,会考虑分两次写。请大家多多关注。

欢迎大家点赞、转发、分享。转载注明出处时要带有原文链接。

shiro入门学习--使用MD5和salt进行加密|练气后期的更多相关文章

  1. Shiro入门学习之shi.ini实现授权(三)

    一.Shiro授权 前提:需要认证通过才会有授权一说 1.授权过程 2.相关方法说明 ①subject.hasRole("role1"):判断是否有该角色 ②subject.has ...

  2. Shiro入门学习与实战(一)

    一.概述 1.Shiro是什么? Apache Shiro是java 的一个安全框架,主要提供:认证.授权.加密.会话管理.与Web集成.缓存等功能,其不依赖于Spring即可使用: Spring S ...

  3. Shiro入门学习之散列算法与凭证配置(六)

    一.散列算法概述 散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,常见的散列算法如MD5.SHA等,一般进行散列时最好提供一个salt(“盐”),什么意思?举个栗子 ...

  4. Shiro入门学习---使用自定义Realm完成认证|练气中期

    写在前面 在上一篇文章<shiro认证流程源码分析--练气初期>当中,我们简单分析了一下shiro的认证流程.不难发现,如果我们需要使用其他数据源的信息完成认证操作,我们需要自定义Real ...

  5. shiro入门学习--授权(Authorization)|筑基初期

    写在前面 经过前面的学习,我们了解了shiro中的认证流程,并且学会了如何通过自定义Realm实现应用程序的用户认证.在这篇文章当中,我们将学习shiro中的授权流程. 授权概述 这里的授权指的是授予 ...

  6. Shiro入门学习之shi.ini实现认证及源码分析(二)

    一.Shiro.ini文件 1.文件说明 ①ini(InitializationFile)初始文件:Window系统文件扩展名 ②Shiro使用时可以连接数据库,也可以不连接数据库(可以使用shiro ...

  7. Shiro入门学习之自定义Realm实现授权(五)

    一.自定义Realm授权 前提:认证通过,查看Realm接口的继承关系结构图如下,要想通过自定义的Realm实现授权,只需继承AuthorizingRealm并重写方法即可 二.实现过程 1.新建mo ...

  8. Shiro入门学习之自定义Realm实现认证(四)

    一.概述 Shirom默认使用自带的IniRealm,IniRealm从ini配置文件中读取用户的信息,而大部分情况下需要从系统数据库中读取用户信息,所以需要实现自定义Realm,Realm接口如下: ...

  9. 在spring security3中使用自定义的MD5和salt进行加密

    首先看代码: <authentication-manager alias="authenticationManager"> <authentication-pro ...

随机推荐

  1. 深入探究.Net Core Configuration读取配置的优先级

    前言     在之前的文章.Net Core Configuration源码探究一文中我们曾解读过Configuration的工作原理,也.Net Core Configuration Etcd数据源 ...

  2. C++中的快读和快写

    快读原理 单个字符的读入速度要比读入数字快,因此我们以字符的形式先读入,然后处理计算转为数字. 代码 inline int read(){ register int x = 0, t = 1; reg ...

  3. mysql 安装卸载自动化脚本

    #!/bin/sh #mkdir /root/mysql #tar -xvf mysql-5.7.-.el7.x86_64.rpm-bundle.tar -C /root/mysql #cd /roo ...

  4. 用java中的Arraylist实现电话本系统管理

    大致思路:创建一个电话本条目的类,在主类中实例化.用实例化的对象调用构造参数接收输入值,然后将此对象存入Arraylist的对象中,实现动态添加电话本条目. 该系统具备添加.删除.修改.查询所有和按姓 ...

  5. 基于PHP实现CMS识别

    最近正在开发一款基于PHP实现的Web安全检测平台,写到了CMS识别这一功能,便写一篇文章总结一下. 首先需要梳理的是CMS识别的几种方法: 1.网页源代码特征:例如源代码中包含CMS的名称或是某种特 ...

  6. Oracle 11G R2安装说明 -九五小庞

    教程版本Oracle 11.2.0.1.0

  7. 免费获取 IntelliJ IDEA 激活码的 6 种方式!

    你还在满世界找 IntelliJ IDEA 激活码? 破解的不稳定,也是违法的,有安全风险还不一定,不建议大家使用来历不明的补丁. 今天栈长就分享免费获取 IntelliJ IDEA 的 6 种方式, ...

  8. Java垃圾回收略略观

    本文主要介绍Java垃圾回收(Garbage Collection),90%干货,文字颇多,需要耐心一点看. [对象判断状态算法] ------引用计数法 在创建对象时,为对象创建一个伴生的引用计数器 ...

  9. Java 根据两个经纬度,得到两点距离

    private static final double EARTH_RADIUS = 6371000;//赤道半径(单位m)private static final double INTEGR_NUM ...

  10. pytest测试框架 -- 简介

    一.pytest测试框架简介: (1)pytest是python的第三方测试框架,是基于unittest的扩展框架,比unittest更简洁,更高效. (2)pytest框架可以兼容unittest用 ...