Shiro学习——MD5加密与盐值

Posted sadoshi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shiro学习——MD5加密与盐值相关的知识,希望对你有一定的参考价值。

前言

上一篇文章讲了shiro如何配置加密服务。这篇文章我们用md5加密算法作为例子。md5算法是常见的加密算法,另外为了提高安全性,通常还会加上盐值。这些如何进行配置呢,在本文进行展示。

加盐值是怎么回事?

像MD5这类加密,对于同一个密码,加密之后的密码都是一样的。如果我们初始化系统,把所有用户设置密码为123456,那经过md5加密之后,所有密文也都是相同的。那盗用者只要破解这个密文,那所有密文相同的帐号也会被盗用。如何避免这种情况呢?加盐。加盐的操作,就是明文加密过程中,把盐(其实就是一小截字符串,例如abc)和明文拼接到一起加密。因为每个帐号的盐值不同,同样明文,加密出来的密文都不一样,这样帐号安全性就大大提高了。

配置用户帐号密码

一开始我是准备把用户名帐号弄在ini文件上的形式,但是折腾了好久都不行。查看了源码,因为一是IniRealm读取ini文件的帐号密码,就没有读取盐值的功能,二是使用的SimpleAccount类存储认证信息也不包含盐值属性。所以如果读者想使用ini文件进行帐号密码管理的话,必须重写这个类的一些方法才行。由于比较麻烦,我就放弃这条路线了。

我选择使用数据库配置帐号密码的形式,这样默认的JdbcRealm是支持包含盐值的密文存储方式。看系列第一篇文章《Shiro学习(一)——Shiro配置与快速开始》,如下图所示,默认users表的password_salt就是存储盐值用的。

 

 接着我们编写生成加密的密文和盐值的方法,这里我们传入123作为密码,以abcd作为盐值,以md5作为加密算法,进行10次加密迭代:

public void encryptMD5(String password) {
	System.out.println("加密后的盐值:"+Base64.encodeToString("abcd".getBytes()));
	SimpleHash hash = new SimpleHash("md5", password, "abcd", 10);	
	System.out.println("加密后的密码:"+hash.toString());
}

执行这段代码,输出结果:

由于JdbcRealm默认会对盐值作Base64解密,我们应该把加密后的盐值写入数据库中,如下图:

 这样准备工作就完成了

初始化配置并测试

下一步,我们通过数据库配置方式,测试认证是否生效。编写如下代码:

public static void main(String[] args) throws Exception {
	DefaultSecurityManager securityManager = new DefaultSecurityManager();
	JdbcRealm realm = new JdbcRealm();
	Class<DruidDataSource> clazz = DruidDataSource.class;
	DruidDataSource dataSource = clazz.newInstance();
	dataSource.setUsername("root");
	dataSource.setPassword("");
	dataSource.setUrl("jdbc:mysql://localhost:3306/shiro");
	dataSource.setDriverClassName("com.mysql.jdbc.Driver");
	realm.setDataSource(dataSource);
	realm.setPermissionsLookupEnabled(true);
	
	HashedCredentialsMatcher cm = new HashedCredentialsMatcher();
	cm.setHashAlgorithmName("md5");
	cm.setHashIterations(10);
	realm.setCredentialsMatcher(cm);
	realm.setSaltStyle(SaltStyle.COLUMN);
	
	securityManager.setRealm(realm);
	SecurityUtils.setSecurityManager(securityManager);
	Subject subject = SecurityUtils.getSubject();
	
	UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
	try {
		subject.login(token);
		System.out.println("ok");
	} catch (AuthenticationException e) {
		e.printStackTrace();
	}
	subject.logout();
}

 2-11行是配置数据库连接的代码,这个我们前面的文章也有讲,就不细述了。13-17行是匹配密码的关键。上一篇文章《Shiro学习(五)——密码的加密解密》我们讲过,密码匹配的关键点之一是CredentialsMatcher接口的实现类。因为这次使用md5加密,所以我们就用HashedCredentialsMatcher类来进行配陪。14行设置加密算法为md5,15行设置迭代次数为10次,这些配置与我们之前加密的方式要一致。16行把HashedCredentialsMatcher配置到jdbcRealm中,当需要匹配帐号密码时,jdbcRealm就会调用HashedCredentialsMatcher了。17行设置加盐方式为SaltStyle.COLUMN。默认情况是SaltStyle.NO_SALT不加盐。

执行代码,如果没其他异常的话,应该会输出ok字样。如果报下图的错误,那就是帐号密码不匹配。这种情况需要检查帐号密码是否配置正确,盐值是否有加密,是否设置了盐值加密方式SaltStyle.COLUMN。

 如果还是找不到,那就要断点到org.apache.shiro.authc.credential.HashedCredentialsMatcher的doCredentialsMatch方法里,看看传入的token(用户提交的信息)与info(数据库获取的信息)是否有问题,再寻找问题出在哪。

小结

这部分内容并不复杂,但是我在使用ini文件配置时卡了很久,另外在盐值也要经过base64加密的问题上也卡了很久。后来都需要通过跟踪源码调试才明白。网上找的文章,绝大多数都是抄来抄去,基本都是自定义一个realm,还把帐号密码盐值写在里面。如果直接搬来改造,还是挺麻烦的。这么简单的业务功能shiro已经提供,我们没必要什么都去扩展,去自定义。

以上是关于Shiro学习——MD5加密与盐值的主要内容,如果未能解决你的问题,请参考以下文章

Shiro___加密加盐迭代

shiro中MessageDigest根据盐值计算md5

MD5盐值加密

md5盐值加密

salt值(盐值)

shiro学习(通俗易懂)