一、目标
1.1 预研需求
数据加密是安全领域中常用的安全措施,它们的主要作用是保护数据的机密性和完整性,以防止未经授权的访问、窃取、篡改或泄漏敏感信息。
数据传输加密:
- 保护敏感数据在传输过程中的安全,当数据通过网络传输时,它们可能会经过多个中间节点,例如路由器、服务器和网络链路,这些节点都有潜在的风险,可能会被黑客或恶意攻击者监视或拦截。
数据存储加密:
- 存储上的备份数据是明文存放的,虽然是通过存储内部的格式存放的,但是通过访问存储介质就能直接读取部分原始内容,不够安全。数据存储加密用于在数据存储介质(例如硬盘、云存储、数据库)上保护数据的安全。即使黑客物理访问了存储设备,也无法轻易获取其中的数据。
1.2 问题描述
- 用户登录、修改密码时,在网络传输过程中没有进行加密处理
- 除了密码是否有其他字段需要加密处理?
二、理论依据
2.1 现有技术分析
数据加密算法:
2.1.1 可逆加密算法
可逆加密算法又分为对称加密算法、非对称加密算法。
2.1.1.1 对称加密算法
对称加密算法是加密和解密使用相同密钥的加密算法。
主要的一些加密算法:
- DES:已破解,很少使用了
- 3DES:早期DES的替代。计算密钥时间太长、加密效率不高,所以也基本上不用
- AES:后期DES的提代。密钥建立时间短、灵敏性好、内存需求低。最常用。
- IDEA:常用的电子邮件加密算法
2.1.1.2 非对称加密算法
非对称加密算法需要两个密钥(公钥和私钥)。公钥与私钥是成对存在的,如果用公钥对数据进行加密,只有对应的私钥才能解密。
主要的一些加密算法:
- DSA:只能用于数字签名,而无法用于加密(某些扩展可以支持加密)
- RSA:即可作为数字签名,也可以作为加密算法。不过作为加密使用的 RSA 有着随密钥长度增加,性能急剧下降的问题。且对内容长度有限制,明文长度=秘钥bit长度值/8-11。1024位的密钥最多只能加密117位(1024/8-11=117)数据,否则就会报错。
2.2.1 不可逆加密算法
相比可逆算法,不可逆算法不支持解密,一旦加密后的结果生成,就无法恢复原始数据。
2.2.1.1 散列算法
又称哈希函数,指纹。把任意长度的输入通过散列算法变换成固定长度的输出,该输出就是散列值(摘要)。
作用:下载一个文件,文件的下载过程中会经过很多网络服务器、路由器的中转,如何保证这个文件下载过程中没有丢包,被完整的下载下来了呢?我们不可能去检测这个文件的每个字节,也不能简单地利用文件名、文件大小这些极容易伪装的信息去判断。这时候,我们就需要一种唯一标志来检查文件的可靠性。
主要的一些加密算法:
- MD5:可产生2进制128位(16进制32位)哈希值。
- SHA:包括SSHA-1、SHA-256、SHA-384、SHA-512等。SHA-1可以产生160位的哈希值,SHA256、SHA384、SHA512可产生256、384、512位的哈希值。
- HMAC:基于哈希函数和密钥的一种消息认证算法。利用哈希运算,以一个密钥和一个消息为输入,生成消息摘要作为输出。需要注意的是,HMAC是信息鉴别码,所以它并不加密信息,而是把经过Hash处理过的信息作为认证码,并且信息必须要和HMAC得到的Hash值一起传输,进行鉴别时,拥有密钥的人对信息再次进行Hash,如果信息没有发生任何改变,得到的Hash值与接收到的Hash值将会是一致的。(类似于加签、验签的一个过程)
2.2.1.2 密码推导函数算法
最常见的就是利用hash算法进行加密,利用hash算法的不可逆性,保护数据信息不被泄露。但是经过hash处理后的密码依然未必安全,常见的有字典破解以及暴力破解,但是由于上述方法算法复杂度过大,当下大多选择更高效的查表法进行处理——包括逆向查表以及彩虹表法。
基于上述问题,我们又产生了新的解决方案。salt是一个随机生成的长字符串,将salt与原始密码连接,对连接后的字符串加密,由于salt的随机性,解决了查表法带来的问题。
主要的一些加密算法:
- PBKDF2:将salted hash进行多次重复计算,其中次数是可定义的。对此算法的时间复杂度进行量化,如果计算一次所需要的时间是1微秒,那么计算1百万次就需要1秒钟。
- Bcrypt:基于Blowfish加密算法改进得到,算法会随机加盐,每次加密后的密文都是不一样的
2.2 现有产品分析
三、技术预研
我们主要研究MD5、RSA两种加密算法
3.1 MD5加密逻辑
前端 MD5加密
// 安装js-md5
// npm i js-md5
import md5 from 'js-md5';
Vue.prototype.$md5Util = md5;
this.$md5Util("请将我这段文字加密")
// 加密结果:aa888a86dca6e9d5ae216c23070e8c47
Java MD5加密
import org.springframework.util.DigestUtils;
public class test{
public static void main(String[] a) {
System.out.println(DigestUtils.md5DigestAsHex("请将我这段文字加密".getBytes()));
// 加密结果:aa888a86dca6e9d5ae216c23070e8c47
}
}
由于MD5是不可逆加密算法,前端经过加密以后,后端没办法解密,也就无法获取到原始数据。
因此,使用MD5加密的数据,后端不需要再次加密,只需要将加密后的数据保留至数据库。后续前端传值,全部为加密数据,后端直接对比和数据库中的值即可。
3.2 RSA加密逻辑
前端 RSA加密、解密
// 安装jsencrypt
// npm i jsencrypt -S
import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'
//公钥
const publicKey = ''
//私钥
const privateKey = ''
// 加密
export function encrypt(txt) {
const encryptor = new JSEncrypt()
encryptor.setPublicKey(publicKey) // 设置公钥
return encryptor.encrypt(txt) // 对数据
}
// 解密(暂无使用)
export function decrypt(txt) {
const encryptor = new JSEncrypt()
encryptor.setPrivateKey(privateKey) // 设置私钥
return encryptor.decrypt(txt) // 对数据进行解密
}
Java RSA加密、解密
import org.apache.tomcat.util.codec.binary.Base64;
import javax.crypto.Cipher;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* @ClassName RSAUtil
* @Description 使用Cipher类实现RSA加密解密
**/
public class RSAUtil {
private static final String privateKey="";
private static final String publicKey="";
/**
* RSA公钥加密
* @param str 加密字符串
* @return 密文
*/
public static String encrypt( String str) throws Exception{
//base64编码的公钥
byte[] decoded = Base64.decodeBase64(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
//RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
return outStr;
}
/**
* RSA私钥解密
* @param str 加密字符串
* @return 铭文
* @throws Exception 解密过程中的异常信息
*/
public static String decrypt(String str) throws Exception{
//64位解码加密后的字符串
byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
//base64编码的私钥
byte[] decoded = Base64.decodeBase64(privateKey);
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
//RSA解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, priKey);
String outStr = new String(cipher.doFinal(inputByte));
return outStr;
}
}
四、结论
进过上面的分析,
在数据传输中:
MD5 较为简单,只需要前端进行数据加密即可。但是安全性较低,一些简单的密码可以通过逆向查表暴力破解。
RSA 需要维护一套公私钥。但是安全性较高。
数据存储加密:
由于存储数据一般都需要使用,需要原始数据,所以基本上不采用不可逆加密算法。可以采用:
AES 对称加密算法,性能好。虽然加密解密使用同一个秘钥,但加密解密过程在同一个系统中,无需担心秘钥丢失问题。
RSA 非对称加密算法, 公钥加密,私钥解密。(加密解密在一个系统中,感觉没有必要采用这种方式)