Java——MD5密码加密
Posted 热爱编程的申同学
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java——MD5密码加密相关的知识,希望对你有一定的参考价值。
目录
1、MD5概述
1.1、什么是MD5?
MD5的全称是Message-Digest Algorithm 5(信息-摘要算法),在90年代初由MIT Laboratory for Computer Science和RSA Data Security Inc的Ronald L. Rivest开发出来,经MD2、MD3和MD4发展而来。
1.2、MD5加密作用
是让大容量信息在用数字签名软件签署私人密匙前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的大整数)。它需要获得一个随机长度的信息并产生一个128位的信息摘要。
1.3、什么要使用MD5加密?
存储一些敏感信息的时候,如果不进行加密肯能会出现安全问题。例如:系统登录的密码,如果数据库中的密码采用明文,一旦数据库泄露,则用户的密码直接泄露。但是使用MD5加密算法之后即使数据泄露,也不会被轻易的破解,相对安全。
2、MD5加密流程
2.1、工具类导入
首先需要在项目中导入MD5的工具类,在用户注册模块中进行使用。
public class MD5Utils
public static String getPWD( String strs )
/*
* 加密需要使用JDK中提供的类
*/
StringBuffer sb = new StringBuffer();
try
MessageDigest digest = MessageDigest.getInstance("MD5");
byte[] bs = digest.digest(strs.getBytes());
/*
* 加密后的数据是-128 到 127 之间的数字,这个数字也不安全。
* 取出每个数组的某些二进制位进行某些运算,得到一个具体的加密结果
*
* 0000 0011 0000 0100 0010 0000 0110 0001
* &0000 0000 0000 0000 0000 0000 1111 1111
* ---------------------------------------------
* 0000 0000 0000 0000 0000 0000 0110 0001
* 把取出的数据转成十六进制数
*/
for (byte b : bs)
int x = b & 255;
String s = Integer.toHexString(x);
if( x > 0 && x < 16 )
sb.append("0");
sb.append(s);
else
sb.append(s);
catch( Exception e)
System.out.println("加密失败");
return sb.toString();
2.2、用户注册模块使用MD5
下面代码是servlet层注册的部分代码,可以看到在使用BeanUtils工具类自动封装后,从前端获取的数据就会被封装到User对象中,此时获取的密码肯定是用户输入的,那么我们在把user对象传递给dao层进行插入之前进行加密,这样就可以实现密码到数据库中时就可以进行MD5加密了
修改代码前
User user=new User();
Map<String, String[]> map = request.getParameterMap();
try
BeanUtils.populate(user,map);
catch (IllegalAccessException e)
e.printStackTrace();
catch (InvocationTargetException e)
e.printStackTrace();
boolean register = userService.register(user);
if(register)
//注册成功,重定向到成功页面
response.sendRedirect("register_success.html");
else
//返回为false说明用户已存在了
request.setAttribute("register_msg","用户已存在,不能重复注册!");
//转发到注册页面
request.getRequestDispatcher("register.jsp").forward(request,response);
在调用service层方法之前加入下面代码,重新为user对象的密码赋值为加密后的密码
user.setPassword(MD5Utils.getPWD(user.getPassword()));
修改代码后
User user=new User();
Map<String, String[]> map = request.getParameterMap();
try
BeanUtils.populate(user,map);
catch (IllegalAccessException e)
e.printStackTrace();
catch (InvocationTargetException e)
e.printStackTrace();
user.setPassword(MD5Utils.getPWD(user.getPassword()));
boolean register = userService.register(user);
if(register)
//注册成功,重定向到成功页面
response.sendRedirect("register_success.html");
else
//返回为false说明用户已存在了
request.setAttribute("register_msg","用户已存在,不能重复注册!");
//转发到注册页面
request.getRequestDispatcher("register.jsp").forward(request,response);
我在注册页面加入一个新的用户admin
可以对比看出,密码就会被加密了,不会以明文的形式展现出来,这样就可以提高数据库信息的安全性。
2.3、登录问题解决
虽然注册功能能够实现加密密码,但是登录功能却会出现问题,因为登录时候需要查询用户名和密码,然而数据库中密码已经被加密了,用户输入的密码肯定不会和加密的密码一致,所以就会出现登录失败的现象。
这是我登录servlet的部分代码,我们只需要在service调用方法之前同样加入一个密码加密就可以了,因为这里的密码也是从前端页面获取的,在进行查询用户账号和密码之前对密码进行加密,结果是一致的。
修改之前
UserService userService = new UserServiceImpl();
HttpSession session = request.getSession();
Map<String, String[]> map = request.getParameterMap();
User user = new User();
try
BeanUtils.populate(user, map);
catch (IllegalAccessException e)
e.printStackTrace();
catch (InvocationTargetException e)
e.printStackTrace();
User user1 = userService.login(user);
if (user1!=null)
//登录成功,重定向到QueryAllServlet中
session.setAttribute("user",user1);
//转发到查询所有
// response.sendRedirect("QueryAllServlet");
//转发到分页查询
response.sendRedirect("QueryStudentByPageServlet");
else
session.setAttribute("msg", "登录失败,用户名或密码错误");
request.getRequestDispatcher("login.jsp").forward(request,response);
修改之后
UserService userService = new UserServiceImpl();
HttpSession session = request.getSession();
Map<String, String[]> map = request.getParameterMap();
User user = new User();
try
BeanUtils.populate(user, map);
catch (IllegalAccessException e)
e.printStackTrace();
catch (InvocationTargetException e)
e.printStackTrace();
user.setPassword(MD5Utils.getPWD(user.getPassword()));
User user1 = userService.login(user);
if (user1!=null)
//登录成功,重定向到QueryAllServlet中
session.setAttribute("user",user1);
//转发到查询所有
// response.sendRedirect("QueryAllServlet");
//转发到分页查询
response.sendRedirect("QueryStudentByPageServlet");
else
session.setAttribute("msg", "登录失败,用户名或密码错误");
request.getRequestDispatcher("login.jsp").forward(request,response);
登录成功!
Java 语言实现 MD5 加密
Java 语言实现 MD5 加密
背景说明
在实际项目中,为了安全性考虑,经常要求账号密码是以加密后的密文形式,保存到数据库中。
这样,即使有人获取到了数据库中的密文密码,也不知道明文密码信息是什么,从而防止系统被恶意访问。
密码加密有很多种方式,比如:Base64,DSA,RSA,MD5,SHA128,SHA256,SHA512等加密方式。
本文主要讲述 MD5 加密方式。
MD5 简介
MD5 消息摘要算法(英文:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。
MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。
MD5应用
1、数据加密
利用它的单向加密性,即不可逆性,我们可以应用于数据和密码的加密。
由于MD5算法的单向性,由MD5码计算出原文几乎是不可能的。目前对于这种加密方法的破解方式是收集常用的密码形式,例如生日,身份证号,电话号码等。把这些收集到的秘密用MD5处理之后进行存储,然后与需要还原的MD5进行比对,当收集的数据达到一定的数目,用户密码被破解的可能性就会变得很大。
对于这种方法,一种加强安全性的方法就是在对用户密码进行MD5处理的时候在原密码上加一个附近值,例如原密码为“password”,处理的时候变为“passworddrowssap”,经过这样的处理之后可以有效降低密码被破解的可能性。
2、确认文件是否被篡改
每个文件都可以计算出一个特定的 MD5 值。
比如,我们上传一个文件到服务器上,可以同时计算出该文件对应的 MD5 值;
在文件下载的时候,通过再次计算该文件的 MD5 值。
如果两个MD5值相同,说明文件没有变化,否则,说明文件被修改过。
Java 语言实现 MD5 加密
通过Java编写程序,实现对任意字符串进行 MD5 加密。
1、第一版代码(初始版)
代码如下:
package com.miracle.luna.md5; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * Created by Miracle Luna on 2019/11/18 */ public class Md5UtilOriginal { /** * 将数据进行 MD5 加密,并以16进制字符串格式输出 * @param data * @return */ public static String md5(String data) { try { byte[] md5 = md5(data.getBytes("utf-8")); return toHexString(md5); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return ""; } /** * 将字节数组进行 MD5 加密 * @param data * @return */ public static byte[] md5(byte[] data) { try { MessageDigest md = MessageDigest.getInstance("md5"); return md.digest(data); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return new byte[]{}; } /** * 将加密后的字节数组,转换成16进制的字符串 * @param md5 * @return */ private static String toHexString(byte[] md5) { StringBuilder sb = new StringBuilder(); System.out.println("md5.length: " + md5.length); for (byte b : md5) { sb.append(Integer.toHexString(b & 0xff)); } return sb.toString(); } public static void main(String[] args) { String password = "password"; String md5HexStr = md5(password); System.out.println("==> MD5 加密前: " + password); System.out.println("==> MD5 加密后: " + md5HexStr); } }
运行结果如下:
md5.length: 16
==> MD5 加密前: password
==> MD5 加密后: 5f4dcc3b5aa765d61d8327deb882cf99
2、第二版代码(精简版)
代码如下:
package com.miracle.luna.md5; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * Created by Miracle Luna on 2019/11/18 */ public class Md5UtilSimple { /** * 将数据进行 MD5 加密,并以16进制字符串格式输出 * @param data * @return */ public static String md5(String data) { StringBuilder sb = new StringBuilder(); try { MessageDigest md = MessageDigest.getInstance("md5"); byte[] md5 = md.digest(data.getBytes(StandardCharsets.UTF_8)); // 将字节数据转换为十六进制 for (byte b : md5) { sb.append(Integer.toHexString(b & 0xff)); } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return sb.toString(); } public static void main(String[] args) { String password = "password"; String md5HexStr = md5(password); System.out.println("==> MD5 加密前: " + password); System.out.println("==> MD5 加密后: " + md5HexStr); } }
运行结果如下:
==> MD5 加密前: password
==> MD5 加密后: 5f4dcc3b5aa765d61d8327deb882cf99
3、第三版代码(最终优化版)
代码如下:
package com.miracle.luna.md5; // 此处需要引入 commons-codec-1.13.jar import org.apache.commons.codec.binary.Hex; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * Created by Miracle Luna on 2019/11/18 */ public class Md5Util { /** * 将数据进行 MD5 加密,并以16进制字符串格式输出 * @param data * @return */ public static String md5(String data) { try { MessageDigest md = MessageDigest.getInstance("MD5"); return Hex.encodeHexString(md.digest(data.getBytes(StandardCharsets.UTF_8))); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return ""; } public static void main(String[] args) { String password = "password"; String md5HexStr = md5(password); System.out.println("==> MD5 加密前: " + password); System.out.println("==> MD5 加密后: " + md5HexStr); } }
运行结果如下:
==> MD5 加密前: password
==> MD5 加密后: 5f4dcc3b5aa765d61d8327deb882cf99
commons-codec-1.13.jar 的 pom 引用如下:
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec --> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.13</version> </dependency>
MD5 在线加密&解密工具
1、MD5 在线加密工具
http://www.bejson.com/enc/md5/ (不仅支持 MD5加密,还支持 Base64,SHA等)
效果如下(在“加密前”后的输入框中输入需要 MD5 加密的字符串 --> 点击“MD5加密” --> 即可在“加密后”的显示显示框中看到加密后的密文):
2、MD5 在线解密
效果如下(输入框中输入需要解密的 MD5 密文,点击解密即可解密 ):
2) https://www.cmd5.com/ (这是一款很强大的解密工具,不仅支持 MD5,还支持SHA的解密)
效果如下(在密文输入框中输入 MD5 密文,点击“解密”,即可看到 MD5 的明文):
解密种类众多,选择范围如下:
MD5 密码安全性优化
由于现在直接将密码用 MD5 算法加密存在一定的安全隐患(被暴力破解的可能性),我们可以根据实际的需要,对密码加密的过程做一些逻辑处理。
比如,如下逻辑处理:
1)password --> Base64 加密,得到加密后的密码A;
2)password --> 翻转得到drowssap --> MD5 加密,得到加密后的密码B;
3)密码A+密码B拼接 --> MD5 加密,得到加密后的密码C;
4)密码C --> 翻转操作,产生密码D,作为最终的密文密码存到数据库中。
这样可以增强密码的安全性,减少被破解的可能性。(此处具体的逻辑优化,可以根据个人喜好和实际需求,灵活定义其变换的复杂性)。
【额外补充】
当密码以 MD5 密文存入到数据库中,用户登录的时候,前端将用户输入的明文密码传输给后端。
后端程序用同样的处理逻辑对其进行 MD5 加密,用加密后的密码与数据库中该用户的密文密码比较。
如果二者相等,说明用户输入的密码正确,允许访问系统;否则,说明密码不正确,禁止访问。
另外,为了系统的安全性考虑,防止恶意暴力尝试破解密码,我们经常限制用户输入密码错误的次数。
比如,连续输入3次或者5次密码,将会自动锁定账号一段时间(根据实际场景,设置锁定时长)。
关于 Base64 加密&解密 的Java 语言实现,请参考博客:https://www.cnblogs.com/miracle-luna/p/11128734.html
希望能帮到大家,谢谢!
以上是关于Java——MD5密码加密的主要内容,如果未能解决你的问题,请参考以下文章