我们知道,编程中数据的传输,保存,为了考虑安全性的问题,需要将数据进行加密.我们拿数据库做例子.如果一个用户注册系统的数据库,没有对用户的信息进行保存,如,我去页面注册,输入"Vicky","123456".注册.web服务器未对数据进行加密而直接写入数据库,那么数据库中的用户信息,便是一个直接可用的数据!一旦服务器服务器被黑~那么用户的信息将毫无保留的展现在黑客面前...为了解决这个弊端,现在大多数都会将信息进行MD5加密.如"Vicky"与"123456"加密后,会生成16位或者32位字符串.而黑客即便获得这些数据也无法使用...
MD5是常用的加密方法,这里主要讲述JDK中的java.security.MessageDigest加密方式!
- @Test
- public void testMD() {
- try {
- String username = "Vicky";
- MessageDigest messageDigest = MessageDigest.getInstance("MD5");
- messageDigest.update(username.getBytes());
- String usernameMD5 = messageDigest.digest().toString();
- System.out.println(usernameMD5);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- @Test
- public void testMD() {
- try {
- String username = "Vicky";
- MessageDigest messageDigest = MessageDigest.getInstance("MD5");
- messageDigest.update(username.getBytes());
- System.out.println(Base64.encode(messageDigest.digest()));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
打印的是:AgwpBZPO+ErqxOosJp0ybQ==
当然我们可以编写函数,处理二进制转hex字符串.
如:
- /**
- * 将16位byte[] 转换为32位String
- *
- * @param buffer
- * @return
- */
- private String toHex(byte buffer[]) {
- StringBuffer sb = new StringBuffer(buffer.length * 2);
- for (int i = 0; i < buffer.length; i++) {
- sb.append(Character.forDigit((buffer[i] & 240) >> 4, 16));
- sb.append(Character.forDigit(buffer[i] & 15, 16));
- }
- return sb.toString();
- }
编写测试语句
- @Test
- public void testMD() {
- try {
- String username = "Vicky";
- MessageDigest messageDigest = MessageDigest.getInstance("MD5");
- messageDigest.update(username.getBytes());
- System.out.println(toHex(messageDigest.digest()));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
打印: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方法!!!
- package cn.vicky.utils;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- /**
- * 令牌处理器
- *
- * @author Vicky
- * @emial eclipser@163.com
- *
- */
- public class TokenProcessor {
- private static TokenProcessor instance = new TokenProcessor();
- private long previous;
- protected TokenProcessor() {
- }
- public static TokenProcessor getInstance() {
- return instance;
- }
- public synchronized String generateToken(String msg, boolean timeChange) {
- try {
- long current = System.currentTimeMillis();
- if (current == previous) current++;
- previous = current;
- MessageDigest md = MessageDigest.getInstance("MD5");
- md.update(msg.getBytes());
- if (timeChange) {
- // byte now[] = (current+"").toString().getBytes();
- byte now[] = (new Long(current)).toString().getBytes();
- md.update(now);
- }
- return toHex(md.digest());
- } catch (NoSuchAlgorithmException e) {
- return null;
- }
- }
- private String toHex(byte buffer[]) {
- StringBuffer sb = new StringBuffer(buffer.length * 2);
- for (int i = 0; i < buffer.length; i++) {
- sb.append(Character.forDigit((buffer[i] & 240) >> 4, 16));
- sb.append(Character.forDigit(buffer[i] & 15, 16));
- }
- return sb.toString();
- }
- }
测试
- @Test
- public void testGenerateToken(){
- String token = new TokenProcessor().generateToken("Vicky",true);
- System.err.println(token);
- String token2 = new TokenProcessor().generateToken("Vicky",false);
- System.err.println(token2);
- }
执行后打印:
69ff8ae72232da59a613ecc830ed7c7a
020c290593cef84aeac4ea2c269d326d
再次执行打印:
d8e38257652deaa76de81c8225801482
020c290593cef84aeac4ea2c269d326d
可见,第1打印的数据,是一直变换的.因为他加入了时间戳
而第2条打印的数据却是不变的,因为他只是简单的MD5加密
这样的安全令牌在很多大型框架中都会涉及,比如说顶顶大名的Struts.这里,我以servlet为实例,向request请求加入安全令牌!
- package cn.vicky.struts.util;
- import java.security.MessageDigest;
- import java.security.NoSuchAlgorithmException;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpSession;
- /**
- *
- * @author Vicky
- * @email eclipser@163.com
- *
- */
- public class TokenProcessor {
- private static TokenProcessor instance = new TokenProcessor();
- private long previous;
- protected TokenProcessor() {
- }
- public static TokenProcessor getInstance() {
- return instance;
- }
- public synchronized boolean isTokenValid(HttpServletRequest request) {
- return isTokenValid(request, false);
- }
- public synchronized boolean isTokenValid(HttpServletRequest request,
- boolean reset) {
- HttpSession session = request.getSession(false);
- if (session == null
- return false;
- String saved = (String) session
- .getAttribute("cn.vicky.struts.action.TOKEN");
- if (saved == null)
- return false;
- if (reset)
- resetToken(request);
- String token = request
- .getParameter("cn.vicky.struts.taglib.html.TOKEN");
- if (token == null)
- return false;
- else
- return saved.equals(token);
- }
- public synchronized void resetToken(HttpServletRequest request) {
- HttpSession session = request.getSession(false);
- if (session == null) {
- return;
- } else {
- session.removeAttribute("cn.vicky.struts.action.TOKEN");
- return;
- }
- }
- public synchronized void saveToken(HttpServletRequest request) {
- HttpSession session = request.getSession();
- String token = generateToken(request);
- if (token != null)
- session.setAttribute("cn.vicky.struts.action.TOKEN", token);
- }
- public synchronized String generateToken(HttpServletRequest request) {
- HttpSession session = request.getSession();
- return generateToken(session.getId());
- }
- public synchronized String generateToken(String id) {
- try {
- long current = System.currentTimeMillis();
- if (current == previous)
- current++;
- previous = current;
- // byte now[] = (current+"").toString().getBytes();
- byte now[] = (new Long(current)).toString().getBytes();
- MessageDigest md = MessageDigest.getInstance("MD5");
- md.update(id.getBytes());
- md.update(now);
- System.out.println(md.digest().length);
- return toHex(md.digest());
- } catch (NoSuchAlgorithmException e) {
- return null;
- }
- }
- private String toHex(byte buffer[]) {
- StringBuffer sb = new StringBuffer(buffer.length * 2);
- for (int i = 0; i < buffer.length; i++) {
- sb.append(Character.forDigit((buffer[i] & 240) >> 4, 16));
- sb.append(Character.forDigit(buffer[i] & 15, 16));
- }
- return sb.toString();
- }
- }