MD5加密不安全?试试加盐,安全提高一个等级!

366 阅读4分钟

image.png

明文处理,经常会谈到MD5加密MD5使用比较广泛的一种加密算法。

本文探讨下,MD5的安全性如何?

先从算法的特点出发。 MD5的特点:

  1. 快速计算:设计初衷就是追求效率。
  2. 哈希冲突:不同的输入,可以生成同样的哈希值。
  3. 长度限制:128位长度。 减少了哈希值的组合数量。

MD5加密后的字符串特征:

  1. 长度固定,32位、16位。其中,16位是截取32位的第9~24位。
  2. 由a-zA-Z和0-9组成的字符串。字母区分大小写,可以分成:16位[小写字母]、16位[大写字母]、32位[小写字母]、32位[大写字母]。

下面我们看看MD5安全性如何。

解密都是有成本的,如果解密成本非常的大,时间成本或存储成本非常的大。解密成本越大,加密算法安全性越高。

下面我们从三种方法看,该算法破解的成本如何:(以12位长度上限的密码大小写字母为例)

1.暴力破解

我们先看例子。电影《模仿游戏》讲述的是二战期间主角被招去破解军事密码,一群顶尖人才做破解工作。主角想到了用机器来代替人做运算,最终密码也破解了。

模仿游戏封面.webp

遍历尝试每一个字符,直到找到正确值为止。 这种方法效率很低,每个字符都需要进行md5计算,再把结果和密文对比。 小结,存储成本较低,只需要一个程序不断的计算即可;密码越长,计算成本越大。

需要运算:(26+26+10)^12+(26+26+10)^11+...个,计算成本大。

2.字典法

把所有可能的密文都算出来,放在一张表里,然后查对应的密文即可。 如果按照12位密码长度(仅大小写字母+数字),就有 (26+26+10)的14次方。 也就是这个表要存那么多数据,才能进行定位查询。 小结,存储成本非常高,需要存储巨大的表数据;密码越长,需要覆盖的字符集越多,存储成本越大。

需要把运算结果都存储起来:(26+26+10)^12+(26+26+10)^11+...个,存储成本大。

3.彩虹表

结合暴力破解和字典法。针对密码的组合,需要预先计算好哈希值的集合。 根据加密算法的特征(比如利用md5的哈希冲突),优化哈希函数,可以有效的减少计算的次数。 通过一种称为“彩虹链”的技术对数据进行压缩,不需要存储所有可能的哈希值集合,只需要存储链表的头和尾,可以节省更多的存储空间。

R函数碰撞-流程标题.png

上图就是彩虹表的过程。

H是摘要信息的哈希函数,也是要破解算法的函数。

R是构建这条链的时候定义的一个函数,它的值域和定义域与 H 函数相反。通过该函数可以将哈希值约简为一个与原文相同格式的值。

重复的部分(上图的虚线部分),通过算法即可优化。这也是彩虹表的方法,通过优化算法,也就是H函数和R函数优化,进一步优化计算能力。

彩虹表破解MD5的成本大大减少,这也导致网上有大量的”在线解密MD5“。

如果项目还是要用MD5加密,建议在原字符串的基础上,拼接多一串静态的字符串或者动态字符串,也就是加盐。

”在线解密MD5“也只能得到,组合过的字符串;管理好”盐“,安全性大大提高。

小结:

如果项目是决定用MD5,建议”加盐“提高安全性。在原字符串的基础上,拼接多一串静态的字符串或者动态字符串。

如果不是必须使用MD5,建议还是使用sha256等加密。毕竟MD5,已经被破解了。在专业的项目中使用,显得我们不是很专业。

u=3552251736,3359140282&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto.webp

最后,附上CryptoJS中的md5源码,也可以点击下面链接查看。

github.com/brix/crypto…

(function (Math) {
    // Shortcuts
    var C = CryptoJS;
    var C_lib = C.lib;
    var WordArray = C_lib.WordArray;
    var Hasher = C_lib.Hasher;
    var C_algo = C.algo;

    // Constants table
    var T = [];

    // Compute constants
    (function () {
        for (var i = 0; i < 64; i++) {
            T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0;
        }
    }());

    /**
     * MD5 hash algorithm.
     */
    var MD5 = C_algo.MD5 = Hasher.extend({
        _doReset: function () {
            this._hash = new WordArray.init([
                0x67452301, 0xefcdab89,
                0x98badcfe, 0x10325476
            ]);
        },

        _doProcessBlock: function (M, offset) {
            ...
        },

        _doFinalize: function () {
            ...
        },

        clone: function () {
            ...
        }
    });

    function FF(a, b, c, d, x, s, t) {
        var n = a + ((b & c) | (~b & d)) + x + t;
        return ((n << s) | (n >>> (32 - s))) + b;
    }

    function GG(a, b, c, d, x, s, t) {
        var n = a + ((b & d) | (c & ~d)) + x + t;
        return ((n << s) | (n >>> (32 - s))) + b;
    }

    function HH(a, b, c, d, x, s, t) {
        var n = a + (b ^ c ^ d) + x + t;
        return ((n << s) | (n >>> (32 - s))) + b;
    }

    function II(a, b, c, d, x, s, t) {
        var n = a + (c ^ (b | ~d)) + x + t;
        return ((n << s) | (n >>> (32 - s))) + b;
    }
    C.MD5 = Hasher._createHelper(MD5);
    C.HmacMD5 = Hasher._createHmacHelper(MD5);
}(Math));