Notes for a front-end developer, esyou.net

0%

如何让MD5加密更加安全?

什么是MD5

MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。
MD5算法具有以下特点:
1、压缩性:任意长度的数据,算出的MD5值长度都是固定的。
2、容易计算:从原数据计算出MD5值很容易。
3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
4、强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。

MD5如此完美

虽然上面把MD5说得这么完美,而且MD5加密是不可逆加密、单向加密(就是说MD5加密后,是无法再通过相关的破解方法破解出明文密码的),但是如果真要破解MD5那也是一件很容易的事情,目前很多网站都提供相关的碰撞解密MD5的功能,因此,简单的字符串MD5加密,很容易就会被破解。那么MD5还能使用吗?肯定是可以使用的,但是必须使用混淆的方法来对加密的数据进行混淆加密。在java开发中经常都会使用混淆加密来加密字符串。如果混淆的字符串被别人发现了,那样也照样是不安全的。

如何让MD5加密更为安全

比如说网站用户密码加密,一般的肯定会想到,直接使用MD5(用户名+密码+”字符串”)的方式进行加密,以增加破解难度。当然这种方法很不错,确实能够保证数据的安全,但是也说不准,假如别人破解了你2个MD5密码的话,那么就会知道,你的加密模式。
因此,我个人建议是使用SHA1+MD5混合加密模式,或者MD5+base64的方式,使用这样的方式后,我们再对最终加密结果进行相应的替换即可得到一个很难破解的密码了。
下面我以java中MD5+base64的方式,编写了一个实例,大家可以学习下这种思路。

1
package com.md5.salt;
2
import java.lang.reflect.Method;  
3
import java.security.NoSuchAlgorithmException;  
4
public class Md5Salt {  
5
    /*MD5加密*/
6
    public static String getMD5(byte[] source) {  
7
        String s = null;  
8
        char hexDigits[] = { '0','a','9','J','4','c','7','W','2','v', 'R','3','h','7','I','5' };// 用来将字节转换成16进制表示的字符  
9
        try {  
10
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");  
11
            md.update(source);  
12
            byte tmp[] = md.digest();// MD5 的计算结果是一个 128 位的长整数,  
13
            // 用字节表示就是 16 个字节  
14
            char str[] = new char[16 * 2];// 每个字节用 16 进制表示的话,使用两个字符, 所以表示成 16  
15
            // 进制需要 32 个字符  
16
            int k = 0;// 表示转换结果中对应的字符位置  
17
            for (int i = 0; i < 16; i++) {// 从第一个字节开始,对 MD5 的每一个字节// 转换成 16  
18
                // 进制字符的转换  
19
                byte byte0 = tmp[i];// 取第 i 个字节  
20
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];// 取字节中高 4 位的数字转换,// >>>  
21
                // 为逻辑右移,将符号位一起右移  
22
                str[k++] = hexDigits[byte0 & 0xf];// 取字节中低 4 位的数字转换  
23
            }  
24
            s = new String(str);// 换后的结果转换为字符串  
25
        } catch (NoSuchAlgorithmException e) {  
26
            // TODO Auto-generated catch block  
27
            //e.printStackTrace();
28
            System.out.println(e);
29
        }  
30
        return s;  
31
    }
32
    /*Base64编码*/
33
    public static String encodeBase64(byte[]input) throws Exception{  
34
        Class clazz=Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");  
35
        Method mainMethod= clazz.getMethod("encode", byte[].class);  
36
        mainMethod.setAccessible(true);  
37
         Object retObj=mainMethod.invoke(null, new Object[]{input});  
38
         return (String)retObj;  
39
    }
40
    /*Test*/
41
    public static void main(String[] args) throws Exception{
42
        /*混淆MD5加密 前字符串+用户名+密码+后字符串*/
43
        String name = "abc";
44
        String keya="@#$&*1029we";
45
        String keyb="})*vbks!1214";
46
        String password = "a123456";
47
        String str =keya+name+password+keyb;
48
        /*为了更加安全,在混洗后的MD5加密前后再添加相应的混淆字符串将32位字符变成52位*/
49
        String test="$a&m|:p"+Md5Salt.getMD5(str.getBytes())+"4r0gf~!*^@j86";
50
        System.out.println(str);
51
        System.out.println("混淆后:"+test);
52
        System.out.println("未混淆的password MD5:"+Md5Salt.getMD5(password.getBytes()));
53
        /*混淆加密后,再进行base64加密得到最终加密结果*/
54
        System.out.println("base64编码后:"+Md5Salt.encodeBase64(test.getBytes()));
55
        System.out.println("base64编码后,再对其相关字母数字进行替换后的结果:"+Md5Salt.encodeBase64(test.getBytes()).replaceAll("X","8").replaceAll("=","k").replaceAll("R","i").replaceAll("2","e").replaceAll("m","c").replaceAll("J","Es"));
56
    }  
57
}

运行以上代码得到如下结果:
@#$&1029weabca123456})*vbks!1214
混淆后:$a&m|:p2a47a377IJcc4W4IWah3a3W94c7J34cJ4r0gf~!
^@j86
未混淆的password MD5:7h42JI20RWR037vI5Wa72h5vWJ7WJv94
base64编码后:
JGEmbXw6cDJhNDdhMzc3SUpjYzRXNElXYWgzYTNXOTRjN0ozNGNKNHIwZ2Z+ISpeQGo4Ng==
base64编码后,再对其相关字母数字进行替换后的结果:
EsGEcb8w6cDEshNDdhMzc3SUpjYzi8NEl8YWgzYTN8OTijN0ozNGNKNHIwZeZ+ISpeQGo4Ngkk
如图:

首先我们将,base64编码后的代码
“JGEmbXw6cDJhNDdhMzc3SUpjYzRXNElXYWgzYTNXOTRjN0ozNGNKNHIwZ2Z+ISpeQGo4Ng==”
,放到网上的base64解密,进行解密,就可以得到混淆后的字符串
“$a&m|:p2a47a377IJcc4W4IWah3a3W94c7J34cJ4r0gf~!*^@j86”
了。怎么样,看来base64编码,可有可无啊。
但是,如果我们队base64的编码结果进行了多次字符替换后,那么解密的的时候会得到什么结果呢?
我们将上面的替换后的base64编码
“EsGEcb8w6cDEshNDdhMzc3SUpjYzi8NEl8YWgzYTN8OTijN0ozNGNKNHIwZeZ+ISpeQGo4Ngkk”
拿去网上进行解密,发现解密出来的要么是乱码,要么就是提示字符串不是base64编码。如下图:

这样一来,我想应该暂时密码是很难被破解的了吧,如果你还害怕不安全,那么再对base64编码后的的内容进行长度截取、或在替换后再进行进行MD5加密一次。

写在最后

一般网站对密码要求不是很高,且有些网站还是明文存储密码,这样对用户的隐私安全造成了不利的因素,但是对于大型网站来说,保证用户数据安全才是硬道理。但所有的加密都只是相对安全的,没有绝对的安全。