写在前面

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

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

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

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

在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并切换掉默认的凭证匹配器

/**自定义Realm对象
* @author 赖柄沣 bingfengdev@aliyun.com
* @version 1.0
* @date 2020/10/4 11:00
*/
public class MySqlRealm extends AuthorizingRealm { public MySqlRealm() {
//设置凭证匹配器,修改为hash凭证匹配器
HashedCredentialsMatcher myCredentialsMatcher = new HashedCredentialsMatcher();
//设置算法
myCredentialsMatcher.setHashAlgorithmName("md5");
//散列次数
myCredentialsMatcher.setHashIterations(1024);
this.setCredentialsMatcher(myCredentialsMatcher);
} /**授权
* @author 赖柄沣 bingfengdev@aliyun.com
* @date 2020-10-04 11:01:50
* @param principalCollection
* @return org.apache.shiro.authz.AuthorizationInfo
* @throws AuthenticationException
* @version 1.0
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { return null;
} /**认证
* @author 赖柄沣 bingfengdev@aliyun.com
* @date 2020-10-04 11:01:50
* @param authenticationToken
* @return org.apache.shiro.authz.AuthorizationInfo
* @throws AuthenticationException
* @version 1.0
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 1. 从token中获取用户名
String principal = (String) authenticationToken.getPrincipal(); //2. 根据用户名查询数据库并封装成authenticationinfo对象返回(模拟)
if (principal == "xiangbei") {
//四个参数分别是数据库中的账号、加密后的密码、盐值、realm名字
AuthenticationInfo authInfo = new SimpleAuthenticationInfo("xiangbei",
"ff595c47b51b4cf70fddce090f68879e",
ByteSource.Util.bytes("ee575f62-0dda-44f2-b75e-4efef795018f"),
this.getName());
return authInfo;
} return null;
}
}

编写认证器

/**认证管理器
* @author 赖柄沣 bingfengdev@aliyun.com
* @version 1.0
* @date 2020/10/4 11:11
*/
public class CurrentSystemAuthenticator {
private DefaultSecurityManager securityManager;
public CurrentSystemAuthenticator() {
//创建安全管理器
securityManager = new DefaultSecurityManager(); //设置自定义realm
this.securityManager.setRealm(new MySqlRealm()); //将安全管理器设置到安全工具类中
SecurityUtils.setSecurityManager(securityManager); } public void authenticate(String username,String password) {
//获取当前登录主题
Subject subject = SecurityUtils.getSubject(); //生成toeken
UsernamePasswordToken token = new UsernamePasswordToken(username, password); //进行认证
try {
subject.login(token);
}catch (UnknownAccountException | IncorrectCredentialsException e) {
System.out.println("用户名或密码不正确");
} //打印认证状态
if (subject.isAuthenticated()){
System.out.println(token.getPrincipal()+" 认证通过!");
}else {
System.out.println(token.getPrincipal()+" 认证未通过!");
} }
}

测试

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

输出

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

输出

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. 好看的css渐变颜色大全网址

    60个渐变颜色 https://webkul.github.io/coolhue/ 60个非常有用的CSS代码片段 https://baijiahao.baidu.com/s?id=160278735 ...

  2. Unity Prefab关联

    Unity3D研究院之Prefab里面的Prefab关联问题http://www.xuanyusong.com/archives/3042

  3. Linux+Jenkins自动构建服务器包

    何时使用: 测试过程中我们需要持续构建一个软件项目,为避免重复的手动下载.解压操作,我们需要搭建一个能够自动构建的测试环境,当代码有更新时,测试人员只需点一下[构建]即可拉取最新的代码进行测试(也可设 ...

  4. 初识ABP vNext(8):ABP特征管理

    Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 定义特征 应用特征 用户数量 社交登录 最后 前言 上一篇提到了ABP功能管理(特征管理),它来自ABP的Featur ...

  5. Mybatis 枚举类处理

    目录 类型处理器(TypeHandler) 内置的枚举处理器 EnumTypeHandler源码 自定义枚举类处理 通用枚举处理器 Git 类型处理器(TypeHandler) 无论是 MyBatis ...

  6. 一文读懂神经网络训练中的Batch Size,Epoch,Iteration

    一文读懂神经网络训练中的Batch Size,Epoch,Iteration 作为在各种神经网络训练时都无法避免的几个名词,本文将全面解析他们的含义和关系. 1. Batch Size 释义:批大小, ...

  7. 判断Java程序是否在jar中运行

    URL url = TextRenderer.class.getResource(""); String protocol = url.getProtocol(); boolean ...

  8. Java Web制作登录 验证码

    具体操作如下: 新建一个servlet,代码如下:标记一个WebServlet, @WebServlet(urlPatterns = {"/checkCode"}) //验证码Se ...

  9. format的实现

    var format = function(s, arg0) { var args = arguments; return s.replace(/\{(\d+)\}/ig, function(a, b ...

  10. 关于在异步操作中访问React事件对象的小问题

    最近撸React的代码时踩了个关于事件处理的坑,场景如下:在监听某个元素上会频繁触发的事件时,我们往往会对该事件的回调函数进行防抖的处理:防抖的包装函数大致长这样: debounce = (fn, d ...