java.security.MessageDigest的使用,MD5,安全密令

专栏收录该内容
58 篇文章 0 订阅

 我们知道,编程中数据的传输,保存,为了考虑安全性的问题,需要将数据进行加密.我们拿数据库做例子.如果一个用户注册系统的数据库,没有对用户的信息进行保存,如,我去页面注册,输入"Vicky","123456".注册.web服务器未对数据进行加密而直接写入数据库,那么数据库中的用户信息,便是一个直接可用的数据!一旦服务器服务器被黑~那么用户的信息将毫无保留的展现在黑客面前...为了解决这个弊端,现在大多数都会将信息进行MD5加密.如"Vicky"与"123456"加密后,会生成16位或者32位字符串.而黑客即便获得这些数据也无法使用...

    MD5是常用的加密方法,这里主要讲述JDK中的java.security.MessageDigest加密方式!

[java]  view plain copy
  1. @Test  
  2.     public void testMD() {  
  3.         try {             
  4.             String username = "Vicky";  
  5.             MessageDigest messageDigest = MessageDigest.getInstance("MD5");  
  6.             messageDigest.update(username.getBytes());  
  7.             String usernameMD5 = messageDigest.digest().toString();  
  8.             System.out.println(usernameMD5);  
  9.         } catch (Exception e) {  
  10.             e.printStackTrace();  
  11.         }  
  12.     }  
打印的是:[B@107077e,这是因为输出的是byte[](messageDigest.digest()得到的是个二进制byte数组,有可能某些byte是不可打印的字符。)...我们可以使用Base64来处理byte[]

[java]  view plain copy
  1. @Test  
  2.     public void testMD() {  
  3.         try {             
  4.             String username = "Vicky";  
  5.             MessageDigest messageDigest = MessageDigest.getInstance("MD5");  
  6.             messageDigest.update(username.getBytes());  
  7.             System.out.println(Base64.encode(messageDigest.digest()));  
  8.         } catch (Exception e) {  
  9.             e.printStackTrace();  
  10.         }  
  11.     }  

打印的是:AgwpBZPO+ErqxOosJp0ybQ== 

当然我们可以编写函数,处理二进制转hex字符串.

如:

[java]  view plain copy
  1. /** 
  2.      * 将16位byte[] 转换为32位String 
  3.      *  
  4.      * @param buffer 
  5.      * @return 
  6.      */  
  7.     private String toHex(byte buffer[]) {  
  8.         StringBuffer sb = new StringBuffer(buffer.length * 2);  
  9.         for (int i = 0; i < buffer.length; i++) {  
  10.             sb.append(Character.forDigit((buffer[i] & 240) >> 416));  
  11.             sb.append(Character.forDigit(buffer[i] & 1516));  
  12.         }  
  13.   
  14.         return sb.toString();  
  15.     }  

编写测试语句

[java]  view plain copy
  1. @Test  
  2.     public void testMD() {  
  3.         try {  
  4.               
  5.             String username = "Vicky";  
  6.             MessageDigest messageDigest = MessageDigest.getInstance("MD5");  
  7.             messageDigest.update(username.getBytes());  
  8.             System.out.println(toHex(messageDigest.digest()));  
  9.         } catch (Exception e) {  
  10.             e.printStackTrace();  
  11.         }  
  12.     }  

打印:020c290593cef84aeac4ea2c269d326d,返回的是32位的字符串!!!

这样我们便可以直接使用JDK为我们提供的加密类与函数了!

 

MessageDigest不仅仅只为我们提供了"MD5"加密,还提供了"SHA-1"

创建的方法只为: MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");

MD5与SHA-1的区别为:MD5是16位,SHA是20位(这是两种报文摘要的算法)

 

难道 MessageDigest 只能用作数据加密吗?如何使用MessageDigest生成安全令牌!!!


 时候,我们需要产生一个数据,这个数据保存了用户的信息,但加密后仍然有可能被人使用,即便他人不确切的了解详细信息...

好比,我们在上网的时候,很多网页都会有一个信息,是否保存登录信息,以便下次可以直接登录而不必再次输入账户,密码等...而通常这样需要Cookie保存用户信息,当然,这个信息是加密信息,且一般都加了时间戳等验证信息的...

    登陆时,读取cookie,解析cookie的信息,以及如时间戳等附加信息.如果没有时间戳...那么任何人只要有这个cookie,复制cookie到他的电脑中,然后登陆相同的页面,即便盗用者并不知道用户的信息是什么,也能登陆...

所以,时间戳就类似我们所说的安全令牌.

    方式,将用户信息MD5加密后,再将时间戳MD5加密,然后按照特定的处理,将加密后的用户信息以及时间戳,ip地址等信息再次处理,加密后,生成cookie保存客户端...这样就避免了前面所说的安全问题...

    java.security.MessageDigest,在创建安全令牌上,比MD5更简便.因为update方法!!!

[java]  view plain copy
  1. package cn.vicky.utils;  
  2.   
  3. import java.security.MessageDigest;  
  4. import java.security.NoSuchAlgorithmException;  
  5.   
  6. /** 
  7.  * 令牌处理器 
  8.  *  
  9.  * @author Vicky 
  10.  * @emial eclipser@163.com 
  11.  *  
  12.  */  
  13. public class TokenProcessor {  
  14.   
  15.     private static TokenProcessor instance = new TokenProcessor();  
  16.   
  17.     private long previous;  
  18.   
  19.     protected TokenProcessor() {  
  20.     }  
  21.   
  22.     public static TokenProcessor getInstance() {  
  23.         return instance;  
  24.     }  
  25.   
  26.     public synchronized String generateToken(String msg, boolean timeChange) {  
  27.         try {  
  28.   
  29.             long current = System.currentTimeMillis();  
  30.             if (current == previous)                current++;   
  31.             previous = current;   
  32.             MessageDigest md = MessageDigest.getInstance("MD5");  
  33.             md.update(msg.getBytes());  
  34.             if (timeChange) {  
  35.                 // byte now[] = (current+"").toString().getBytes();  
  36.                 byte now[] = (new Long(current)).toString().getBytes();  
  37.                 md.update(now);  
  38.             }  
  39.             return toHex(md.digest());  
  40.         } catch (NoSuchAlgorithmException e) {  
  41.             return null;  
  42.         }  
  43.     }  
  44.   
  45.     private String toHex(byte buffer[]) {  
  46.         StringBuffer sb = new StringBuffer(buffer.length * 2);  
  47.         for (int i = 0; i < buffer.length; i++) {  
  48.             sb.append(Character.forDigit((buffer[i] & 240) >> 416));  
  49.             sb.append(Character.forDigit(buffer[i] & 1516));  
  50.         }  
  51.   
  52.         return sb.toString();  
  53.     }  
  54. }  

测试

[java]  view plain copy
  1. @Test  
  2.     public void testGenerateToken(){  
  3.           
  4.         String token = new TokenProcessor().generateToken("Vicky",true);  
  5.           
  6.         System.err.println(token);  
  7.   
  8.         String token2 = new TokenProcessor().generateToken("Vicky",false);  
  9.           
  10.         System.err.println(token2);  
  11.     }  
  12.       

执行后打印:

69ff8ae72232da59a613ecc830ed7c7a
020c290593cef84aeac4ea2c269d326d

再次执行打印:

d8e38257652deaa76de81c8225801482
020c290593cef84aeac4ea2c269d326d

可见,第1打印的数据,是一直变换的.因为他加入了时间戳

而第2条打印的数据却是不变的,因为他只是简单的MD5加密

 

   这样的安全令牌在很多大型框架中都会涉及,比如说顶顶大名的Struts.这里,我以servlet为实例,向request请求加入安全令牌!

[java]  view plain copy
  1. package cn.vicky.struts.util;  
  2.   
  3. import java.security.MessageDigest;  
  4. import java.security.NoSuchAlgorithmException;  
  5.   
  6. import javax.servlet.http.HttpServletRequest;  
  7. import javax.servlet.http.HttpSession;  
  8.   
  9. /** 
  10.  *  
  11.  * @author Vicky 
  12.  * @email eclipser@163.com 
  13.  *  
  14.  */  
  15. public class TokenProcessor {  
  16.   
  17.     private static TokenProcessor instance = new TokenProcessor();  
  18.   
  19.     private long previous;  
  20.   
  21.     protected TokenProcessor() {  
  22.     }  
  23.   
  24.     public static TokenProcessor getInstance() {  
  25.         return instance;  
  26.     }  
  27.   
  28.     public synchronized boolean isTokenValid(HttpServletRequest request) {  
  29.         return isTokenValid(request, false);  
  30.     }  
  31.   
  32.     public synchronized boolean isTokenValid(HttpServletRequest request,  
  33.             boolean reset) {  
  34.   
  35.         HttpSession session = request.getSession(false);  
  36.         if (session == null  
  37.             return false;  
  38.         String saved = (String) session  
  39.                 .getAttribute("cn.vicky.struts.action.TOKEN");  
  40.         if (saved == null)   
  41.             return false;  
  42.   
  43.         if (reset)   
  44.             resetToken(request);  
  45.         String token = request  
  46.                 .getParameter("cn.vicky.struts.taglib.html.TOKEN");  
  47.         if (token == null)  
  48.             return false;  
  49.         else  
  50.             return saved.equals(token);   
  51.     }  
  52.   
  53.   
  54.     public synchronized void resetToken(HttpServletRequest request) {  
  55.         HttpSession session = request.getSession(false);  
  56.         if (session == null) {  
  57.             return;  
  58.         } else {  
  59.             session.removeAttribute("cn.vicky.struts.action.TOKEN");  
  60.             return;  
  61.         }  
  62.     }  
  63.   
  64.   
  65.     public synchronized void saveToken(HttpServletRequest request) {  
  66.         HttpSession session = request.getSession();  
  67.         String token = generateToken(request);  
  68.         if (token != null)  
  69.             session.setAttribute("cn.vicky.struts.action.TOKEN", token);  
  70.     }  
  71.   
  72.   
  73.     public synchronized String generateToken(HttpServletRequest request) {  
  74.         HttpSession session = request.getSession();  
  75.         return generateToken(session.getId());  
  76.     }  
  77.   
  78.   
  79.     public synchronized String generateToken(String id) {  
  80.         try {  
  81.   
  82.             long current = System.currentTimeMillis();  
  83.             if (current == previous)   
  84.                 current++;  
  85.             previous = current;  
  86.               
  87.             // byte now[] = (current+"").toString().getBytes();  
  88.             byte now[] = (new Long(current)).toString().getBytes();  
  89.             MessageDigest md = MessageDigest.getInstance("MD5");  
  90.               
  91.             md.update(id.getBytes());  
  92.             md.update(now);  
  93.             System.out.println(md.digest().length);  
  94.             return toHex(md.digest());  
  95.         } catch (NoSuchAlgorithmException e) {  
  96.             return null;  
  97.         }  
  98.     }  
  99.   
  100.       
  101.     private String toHex(byte buffer[]) {  
  102.         StringBuffer sb = new StringBuffer(buffer.length * 2);  
  103.         for (int i = 0; i < buffer.length; i++) {  
  104.             sb.append(Character.forDigit((buffer[i] & 240) >> 416));  
  105.             sb.append(Character.forDigit(buffer[i] & 1516));  
  106.         }  
  107.   
  108.         return sb.toString();  
  109.     }  
  110. }  



  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值