前端也需要了解的加密知识

360 阅读20分钟

前言

加密用来干什么?

在一定的业务范围内,我们前端可能使用加密相关的知识比较的少,但是不可避免的在一些时候还是需要对加密有一定的认知,比如订单信息,用户账号信息,秘钥信息等等。下面介绍一下比较常见的加密方式,后续更新中🍗...

base64

简介

1个字母字符 = 1个字节(byte) = 8位(bit),这是表示单位.

base64是网络上最常见的用于传输 8 bit的编码方式之一,base64就是一种基于64个可打印字符来表示二进制数据的方法。

image.png

在一些网络传送渠道,有时候有些的字节字符不能被支持。比如图片的二进制流的每个字节不可能全部是可见字符,这种情况下传送不了。而base64的机制就能很好解决这种问题,它不改变原来的协议,在原来的基础做一种扩展,基于64个可打印字符来表示二进制。

再者,有时候我们通过记事本去打开一些图片或者应用程序,会得到一大堆看不懂的乱码,因为二进制文件里面有很多无法显示和打印的字符,所以如果要让记事本能够处理二进制数据,就可以使用base64来进行转码,将不可见的转成可见的。

算法原理

  1. 我们拿到一串字符,比如 abcdef先按ASCII码编码;
  2. 它会将字符串按字节数分开,每三个字节为一组;
3 byte * 8 bit === 24bit.
  1. 在这组中,将24位数据按照每6位为一组,再次分成4组;
  2. 然后将这四组的6位数的高位各补两个0,将其转为十进制数;
  3. 进行查表,得到对应的字符,就是对应的base64转化的字符。

image.png

那么有个问题来了,如果原始数据的位数不是3的整数倍怎么办,base64会在不足的后面用"="补足,所以这个"="只会存在在base64码的最后,并且只会有1或者2个,不可能出现在中间。

image.png

代码实现

// javaScript实现

if (!Shotgun)
    var Shotgun = {};
if (!Shotgun.Js)
    Shotgun.Js = {};
Shotgun.Js.Base64 = {
    _table: [
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
        'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
        'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
        'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
    ],
  
    encode: function (bin) {
        var codes = [];
        var un = 0;
        un = bin.length % 3;
        if (un == 1)
            bin.push(0, 0);
        else if (un == 2)
            bin.push(0);
        for (var i = 2; i < bin.length; i += 3) {
            var c = bin[i - 2] << 16;
            c |= bin[i - 1] << 8;
            c |= bin[i];
            codes.push(this._table[c >> 18 & 0x3f]);
            codes.push(this._table[c >> 12 & 0x3f]);
            codes.push(this._table[c >> 6 & 0x3f]);
            codes.push(this._table[c & 0x3f]);
        }
        if (un >= 1) {
            codes[codes.length - 1] = "=";
            bin.pop();
        }
        if (un == 1) {
            codes[codes.length - 2] = "=";
            bin.pop();
        }
        return codes.join("");
    },
    decode: function (base64Str) {
        var i = 0;
        var bin = [];
        var x = 0, code = 0, eq = 0;
        while (i < base64Str.length) {
            var c = base64Str.charAt(i++);
            var idx = this._table.indexOf(c);
            if (idx == -1) {
                switch (c) {
                    case '=': idx = 0; eq++; break;
                    case ' ':
                    case '\n':
                    case "\r":
                    case '\t':
                        continue;
                    default:
                        throw { "message": "\u0062\u0061\u0073\u0065\u0036\u0034\u002E\u0074\u0068\u0065\u002D\u0078\u002E\u0063\u006E\u0020\u0045\u0072\u0072\u006F\u0072\u003A\u65E0\u6548\u7F16\u7801\uFF1A" + c };
                }
            }
            if (eq > 0 && idx != 0)
                throw { "message": "\u0062\u0061\u0073\u0065\u0036\u0034\u002E\u0074\u0068\u0065\u002D\u0078\u002E\u0063\u006E\u0020\u0045\u0072\u0072\u006F\u0072\u003A\u7F16\u7801\u683C\u5F0F\u9519\u8BEF\uFF01" };
  
            code = code << 6 | idx;
            if (++x != 4)
                continue;
            bin.push(code >> 16);
            bin.push(code >> 8 & 0xff);
            bin.push(code & 0xff)
            code = x = 0;
        }
        if (code != 0)
            throw { "message": "\u0062\u0061\u0073\u0065\u0036\u0034\u002E\u0074\u0068\u0065\u002D\u0078\u002E\u0063\u006E\u0020\u0045\u0072\u0072\u006F\u0072\u003A\u7F16\u7801\u6570\u636E\u957F\u5EA6\u9519\u8BEF" };
        if (eq == 1)
            bin.pop();
        else if (eq == 2) {
            bin.pop();
            bin.pop();
        } else if (eq > 2)
            throw { "message": "\u0062\u0061\u0073\u0065\u0036\u0034\u002E\u0074\u0068\u0065\u002D\u0078\u002E\u0063\u006E\u0020\u0045\u0072\u0072\u006F\u0072\u003A\u7F16\u7801\u683C\u5F0F\u9519\u8BEF\uFF01" };
  
        return bin;
    }
};

应用

  • base64编码可用于在HTTP环境下传递较长的标识信息。
  • 电子邮件:有些文本协议不支持不可见字符的传递,只能用大于32的可见字符来传递信息。
  • base64 也会经常用作一个简单的“加密”来保护某些数据,而真正的加密通常都比较繁琐。
  • 垃圾讯息传播者用base64来避过反垃圾邮件工具,因为那些工具通常都不会翻译base64的讯息。
  • 前端在实现页面一些比较小的图片,通常会选择将图片内容直接内嵌在页面中,避免不必要的外部资源加载,增大页面加载时间,但是图片数据是二进制数据,该怎么嵌入呢?绝大多数现代浏览器都支持一种名为 Data URLs 的特性,允许使用base64对图片或其他文件的二进制数据进行编码,将其作为文本字符串嵌入网页中。比如webpack工具中的url-loader默认将8kb以下的图片编译成base64码嵌在引用文件中.

前端使用

crypto-js

功能强大,不止处理base64,支持的模块非常多,star数目前6k+,前后端可用。

//后端 npm包管理
npm install crypto-js

import sha256 from 'crypto-js/sha256';
import hmacSHA512 from 'crypto-js/hmac-sha512';
import Base64 from 'crypto-js/enc-base64';

const message, nonce, path, privateKey; // ...
const hashDigest = sha256(nonce + message);
const hmacDigest = Base64.stringify(hmacSHA512(path + hashDigest, privateKey));

//前端 Brower管理
bower install crypto-js

js-Base64
专门处理base64,目前star数2k+,前后端均可用

//安装
$ npm install --save js-base64
//如果你使用的es6语法,需要转载这个进行语法转换
$ npm install --save babel-preset-env

//node.js
var Base64 = require('js-base64').Base64;
//es6+
import { Base64 } from 'js-base64';

//非常轻快的使用体验
Base64.encode('dankogai');  // ZGFua29nYWk=
Base64.encode('小飼弾');    // 5bCP6aO85by+
Base64.encodeURI('小飼弾'); // 5bCP6aO85by-

解密

如果你看懂了以上的算法原理,那么解密其实不是太大的问题,只要你遵循这个规则进行逆推运算,就可以得到原始数据。所以严格上说base64并不是什么加密,只是编译过后的并不是明文而已。

MD5

简介

MD5是一种信息摘要算法(Message-Digest Algorithm),可以产生出一个128bit的散列值(hash)。

12345   MD5===> e10adc3949ba59abbe56e057f20f883e
// 说好的128位,为什么有32个字符.
//这串码是16进制表示,1位==4位二进制.

源于其算法,不管是对于多大的文件数据进行MD5加密,所得到结果的长度都是32个字符(1个中文字符等于2个字节,一个字母字符等于一个字节)。对于内容相同的数据进行加密,得到的结果必然是相同的,如果内容有改动,哪怕是一个字节,其MD5值也会改动。

所以也可以说MD5是有损算法,在一定程度有丢失。举一个假设就是压缩文件,前后可以进行压缩和解压,并且内容是不可以丢失的,如果采用MD5来做,那么解压后肯定有一部分的数据丢失了,肯定不可取。

所以MD5的结果是不可逆运算的,也就是几乎不可能通过MD5值去逆推出原始数据。因为不管是多大的文件最终都是转化成128位的值,所以现实是可能存在有不同的原始数据被转化成同样的MD5值的。但是想主动搜寻两个不同的数据,让他们具有相同的MD5值,是非常困难。或者有一个原始数据和它的MD5数据,想再找一个和其MD5数据一样的原始数据也几乎是不可能的。

但是并不是说MD5是完全不可破解的.有专业的黑客甚至普通黑客也可以利用MD5值实际是有损压缩技术这一原理,将MD5的逆运算的值作为一张表俗称彩虹表的散列表来破解密码。市面上也有不少的MD5破解网站,大体的原理类似,通过查字典的方式去查找。

应用

一致性检验

比如说在进行文件下载的时候,会生成文件内容的MD5值。等到文件完整下载的时候,再用该文件得出MD5值和之前的文件的MD5值进行对比,用以确认文件的内容的一致性。

有很多时候,你会发现网络上的很多文件的命名都是一段hash值加后缀名的方式。这样处理的好处是能在一定的程度上避免同名,更大的用处是能够根据其文件内容来获取专属的MD5值来命名。这样做,可以算是以内容来命名,可以一定程度上避免资源的浪费,重复的文件。

所以说,MD5有点类似"指纹",每一个都独一无二。只要内容不一致,就产生不一样的MD5值。

利用MD5算法来进行文件校验的方案被大量应用到软件下载站、论坛数据库、系统文件安全等方面.

数字签名

MD5的典型应用是对一段字符串(重要隐私信息)产生,以防止被“篡改”。 你将一段话写在一个文件中,并产生一个MD5的值并记录在案,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内容,你对这个文件重新计算MD5时就会发现(两个MD5值不相同)。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。

安全访问认证

在现实的大部分场景都有登录的需要.当用户登录的时候,系统把用户输入的密码进行MD5 Hash运算,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这可以避免用户的密码被具有系统管理员权限的用户知道。

原理

MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

引用自-刘俊辉. MD5 消息摘要算法实现及改进[J]. 福建电脑, 2007 (4): 92-93.

function md5(string) {
    function md5_RotateLeft(lValue, iShiftBits) {
        return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
    }
    function md5_AddUnsigned(lX, lY) {
        var lX4, lY4, lX8, lY8, lResult;
        lX8 = (lX & 0x80000000);
        lY8 = (lY & 0x80000000);
        lX4 = (lX & 0x40000000);
        lY4 = (lY & 0x40000000);
        lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
        if (lX4 & lY4) {
            return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
        }
        if (lX4 | lY4) {
            if (lResult & 0x40000000) {
                return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
            } else {
                return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
            }
        } else {
            return (lResult ^ lX8 ^ lY8);
        }
    }
    function md5_F(x, y, z) {
        return (x & y) | ((~x) & z);
    }
    function md5_G(x, y, z) {
        return (x & z) | (y & (~z));
    }
    function md5_H(x, y, z) {
        return (x ^ y ^ z);
    }
    function md5_I(x, y, z) {
        return (y ^ (x | (~z)));
    }
    function md5_FF(a, b, c, d, x, s, ac) {
        a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_F(b, c, d), x), ac));
        return md5_AddUnsigned(md5_RotateLeft(a, s), b);
    };
    function md5_GG(a, b, c, d, x, s, ac) {
        a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_G(b, c, d), x), ac));
        return md5_AddUnsigned(md5_RotateLeft(a, s), b);
    };
    function md5_HH(a, b, c, d, x, s, ac) {
        a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_H(b, c, d), x), ac));
        return md5_AddUnsigned(md5_RotateLeft(a, s), b);
    };
    function md5_II(a, b, c, d, x, s, ac) {
        a = md5_AddUnsigned(a, md5_AddUnsigned(md5_AddUnsigned(md5_I(b, c, d), x), ac));
        return md5_AddUnsigned(md5_RotateLeft(a, s), b);
    };
    function md5_ConvertToWordArray(string) {
        var lWordCount;
        var lMessageLength = string.length;
        var lNumberOfWords_temp1 = lMessageLength + 8;
        var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
        var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
        var lWordArray = Array(lNumberOfWords - 1);
        var lBytePosition = 0;
        var lByteCount = 0;
        while (lByteCount < lMessageLength) {
            lWordCount = (lByteCount - (lByteCount % 4)) / 4;
            lBytePosition = (lByteCount % 4) * 8;
            lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
            lByteCount++;
        }
        lWordCount = (lByteCount - (lByteCount % 4)) / 4;
        lBytePosition = (lByteCount % 4) * 8;
        lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
        lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
        lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
        return lWordArray;
    };
    function md5_WordToHex(lValue) {
        var WordToHexValue = "",
        WordToHexValue_temp = "",
        lByte, lCount;
        for (lCount = 0; lCount <= 3; lCount++) {
            lByte = (lValue >>> (lCount * 8)) & 255;
            WordToHexValue_temp = "0" + lByte.toString(16);
            WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
        }
        return WordToHexValue;
    };
    function md5_Utf8Encode(string) {
        string = string.replace(/\r\n/g, "\n");
        var utftext = "";
        for (var n = 0; n < string.length; n++) {
            var c = string.charCodeAt(n);
            if (c < 128) {
                utftext += String.fromCharCode(c);
            } else if ((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            } else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }
        }
        return utftext;
    };
    var x = Array();
    var k, AA, BB, CC, DD, a, b, c, d;
    var S11 = 7,
    S12 = 12,
    S13 = 17,
    S14 = 22;
    var S21 = 5,
    S22 = 9,
    S23 = 14,
    S24 = 20;
    var S31 = 4,
    S32 = 11,
    S33 = 16,
    S34 = 23;
    var S41 = 6,
    S42 = 10,
    S43 = 15,
    S44 = 21;
    string = md5_Utf8Encode(string);
    x = md5_ConvertToWordArray(string);
    a = 0x67452301;
    b = 0xEFCDAB89;
    c = 0x98BADCFE;
    d = 0x10325476;
    for (k = 0; k < x.length; k += 16) {
        AA = a;
        BB = b;
        CC = c;
        DD = d;
        a = md5_FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
        d = md5_FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
        c = md5_FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
        b = md5_FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
        a = md5_FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
        d = md5_FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
        c = md5_FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
        b = md5_FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
        a = md5_FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
        d = md5_FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
        c = md5_FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
        b = md5_FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
        a = md5_FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
        d = md5_FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
        c = md5_FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
        b = md5_FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
        a = md5_GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
        d = md5_GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
        c = md5_GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
        b = md5_GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
        a = md5_GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
        d = md5_GG(d, a, b, c, x[k + 10], S22, 0x2441453);
        c = md5_GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
        b = md5_GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
        a = md5_GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
        d = md5_GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
        c = md5_GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
        b = md5_GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
        a = md5_GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
        d = md5_GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
        c = md5_GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
        b = md5_GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
        a = md5_HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
        d = md5_HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
        c = md5_HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
        b = md5_HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
        a = md5_HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
        d = md5_HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
        c = md5_HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
        b = md5_HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
        a = md5_HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
        d = md5_HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
        c = md5_HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
        b = md5_HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
        a = md5_HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
        d = md5_HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
        c = md5_HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
        b = md5_HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
        a = md5_II(a, b, c, d, x[k + 0], S41, 0xF4292244);
        d = md5_II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
        c = md5_II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
        b = md5_II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
        a = md5_II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
        d = md5_II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
        c = md5_II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
        b = md5_II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
        a = md5_II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
        d = md5_II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
        c = md5_II(c, d, a, b, x[k + 6], S43, 0xA3014314);
        b = md5_II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
        a = md5_II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
        d = md5_II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
        c = md5_II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
        b = md5_II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
        a = md5_AddUnsigned(a, AA);
        b = md5_AddUnsigned(b, BB);
        c = md5_AddUnsigned(c, CC);
        d = md5_AddUnsigned(d, DD);
    }
    return (md5_WordToHex(a) + md5_WordToHex(b) + md5_WordToHex(c) + md5_WordToHex(d)).toLowerCase();
}

前端使用

JavaScript-MD5

功能单一,专门处理MD5。star数目前3k+,使用非常简单,并且前后端都可用。

//前端
<script src="js/md5.min.js"></script>
var hash = md5("value"); // "2063c1608d6e0baf80249c42e2be5804"

//后端
npm install blueimp-md5

require("http").createServer(function (req, res) {
    // The md5 module exports the md5() function:
    var md5 = require("./md5"),
    // Use the following version if you installed the package with npm:
    // var md5 = require("blueimp-md5"),
        url  = require("url"),
        query = url.parse(req.url).query;
    res.writeHead(200, {"Content-Type": "text/plain"});
    // Calculate and print the MD5 hash of the url query:
    res.end(md5(query));
}).listen(8080, "localhost");
console.log("Server running at http://localhost:8080/");

crypto-js

功能强大,不止处理MD5,支持的模块非常多,star数目前6k+,前后端可用。

//后端 npm包管理
npm install crypto-js

import sha256 from 'crypto-js/sha256';
import hmacSHA512 from 'crypto-js/hmac-sha512';
import Base64 from 'crypto-js/enc-base64';

const message, nonce, path, privateKey; // ...
const hashDigest = sha256(nonce + message);
const hmacDigest = Base64.stringify(hmacSHA512(path + hashDigest, privateKey));

//前端 Brower管理
bower install crypto-js

提高安全性

加盐

如果想提高你的安全性,那么可以采取再进一步对原始数据进行“加盐”,“盐”就是一串比较复杂的字符串。你所添加的"盐"越长越复杂,加密后破解起来就越麻烦。你可以尝试下在原始数据上加一串复杂的字符串,然后再去进行MD5加密。这样即使解开MD5,也不能知道你的原始数据到底是那一段。

但是即使这样也不可能绝对是绝对安全.这个“盐”还是有泄漏的风险。比如苹果端、安卓端、前端、后台等等那些个技术人员都是知道的,都有可能泄漏出去。放在服务器也不绝对安全,也有手段去抓取。

但是相对的还是进一步的提高了加密的安全性。

SHA

简介

SHA家族的五个算法,分别是SHA-1、SHA-224、SHA-256、SHA-384,和SHA-512,由美国安全局(NSA)所设计,并由美国国家标准与技术研究院(NIST)发布;是美国的政府标准。后四者有时并称为SHA-2。

SHA-1,哈希(Hash)算法,一个非常流行的加密散列函数。在许多安全协议中广为使用,通常被用做密码加密,文件校验等,曾被视为MD5的后继者,且存在不可逆性。(和MD5同为MD4导出,所以具备一定的相似性)

这个算法的思想是输入长度不限的明文,产出一个160位的信息摘要(比MD5多出32位)。也是会压缩原来的内容,输出固定长度的散列值。在一定的强度上,它比MD5的强度更高。

早在05年的时候,我国的王小云教授成功的提出了MD5成功碰撞.(不同的原始数据得到相同的密文),继而又提出了sha1的碰撞,可是并无实例.

在2017年,谷歌成功的对SHA-1进行了碰撞,当时震动了世界,也就是说SHA-1算法不再那么安全。

其成功碰撞,能使用两个不同的原始数据得到相同的摘要,这个时候,如果有恶意攻击者使用这种冲突,用恶意文件来替换掉安全文件,而接收者通过相同的信息摘要,并不能识别出来文件的性质,可能造成严重的后果。

但是对于SHA-1的破解难度还是有一定的难度,需要相当的条件才能有具备这个能力。

下面的列出了一些数字,让大家了解破解这种算法所需要的计算规模有多大: 总计900万兆(即百万的五次幂,具体为9,223,372,036,854,775,808)次SHA1计算。 要完成攻击的首个阶段需要单一CPU计算6500年。 要完成攻击的第二阶段需要单一GPU计算110年。

md5:只需要一个智能手机30秒就破解了。 sha-1 shattered:110GPU 需要一年; sha-1 bruteforce:12000000GPU 需要一年。

总之,就是也就只有谷歌这些云计算基础设施才能搞得定,不是谁都可以.而且后面还有更为安全的sha2算法.

所以从2017年1月发布的第56版开始,Chrome会将任何受SHA-1证书保护的网站视为不安全。 Firefox已计划于2017年初推出此功能,已于2017年2月24日淘汰了SHA-1

前端使用

crypto-js

功能强大,不止处理MD5,支持的模块非常多,star数目前6k+,前后端可用。

//后端 npm包管理
npm install crypto-js

import sha256 from 'crypto-js/sha256';
import hmacSHA512 from 'crypto-js/hmac-sha512';
import Base64 from 'crypto-js/enc-base64';

const message, nonce, path, privateKey; // ...
const hashDigest = sha256(nonce + message);
const hmacDigest = Base64.stringify(hmacSHA512(path + hashDigest, privateKey));

//前端 Brower管理
bower install crypto-js

jsSHA

专注处理sha加密,目前star数1k+。能够处理sha家族(SHA-1、SHA-224、SHA3-224、SHA-256、SHA3-256、SHA-384、SHA3-384、SHA-512、SHA3-512、SHAKE128、和SHAKE256以及HMAC)。

npm install jssha
//引用
jsSHA = require("jssha");
//使用
var shaObj = new jsSHA("SHA-512", "TEXT");
shaObj.update("This is a ");
shaObj.update("test");
var hash = shaObj.getHash("HEX");