密码不加密,要你有何用

85 阅读2分钟

前言

  • 网站登录被攻破,老板深夜把我召回。不知道你有没有遇到过这种刺激的夜晚。

加密

  • 经过一夜的定位终于知道是我们网站涉及时图简单采用的是简单的加密方式密码,很容易就被别人攻击破解了。
  • 今天我们来看看如何实现密码的加密解密更加的高大上呢
  • data:首先我们需要被加密的原始数据。
  • charset:还需要一个转码字符集,我们可以叫他为charset
  • algorithm:因为目前加密方式有很多中,我们这里在提供一个字段用作加密方式,目前有MD5,SHA,SHA1,SHA-1,SHA-256,SHA-384,SHA-512
  • toLowerCase:再提供一个字段用作指定是否返回小写形式的十六进制字符串
public String getHexSign(String data, String charset, String algorithm, boolean toLowerCase){
    char[] DIGITS_LOWER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    char[] DIGITS_UPPER = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    //Used to build output as Hex
    char[] DIGITS = toLowerCase ? DIGITS_LOWER : DIGITS_UPPER;
    //get byte[] from {@link TradePortalUtil#getBytes(String, String)}
    byte[] dataBytes = getBytes(data, charset);
    byte[] algorithmData = null;
    try {
        //get an algorithm digest instance
        algorithmData = MessageDigest.getInstance(algorithm).digest(dataBytes);
    } catch (NoSuchAlgorithmException e) {
        logger.error("签名字符串[" + data + "]时发生异常:System doesn't support this algorithm[" + algorithm + "]");
        return "";
    }
    char[] respData = new char[algorithmData.length << 1];
    //two characters form the hex value
    for(int i=0,j=0; i<algorithmData.length; i++){
        respData[j++] = DIGITS[(0xF0 & algorithmData[i]) >>> 4];
        respData[j++] = DIGITS[0x0F & algorithmData[i]];
    }
    return new String(respData);
}
  • 这里支持多种加密方式得力于MesageDigest这个优秀的类,在他的内部会内置这些加密器

image-20211020164455486.png

生成带时间戳的密码

使用时间戳,目前使用非常广泛 思路:

  • 客户端注册时输入账号和原始密码,服务器会返回一个key给客户端
  • 服务器将账号,key,以及hmac后的密码(EncryptPass)保存在数据库
  • 客户端拿到key后,会将原始密码结合key进行一次hmac运算,生成一个加密后的密码
  • (EncryptPass),加密后的密码再结合当前时间(这个时间要从服务器获取)再做一次md5,生成新的加密密码(finalPass)
  • 客户端结合时间生产密码后,会发送请求和服务器上的密码作比较(服务器会用EncryptPass结合服务器当前时间,或者当前时间前一分钟,生产服务器的finalPass,如果这两个时间相同,就登陆成功)
  • 这样根据时间来做,就算暴力破解或者模拟登陆,已经过了时效了,密码早已经变了。