最近安全测试的总是测出安全漏洞来,让开发改。
想了想干脆把请求参数都加密下,前端加密后端解密,这样总差不多了。
看了下AES加密,是对称的,前后端用这个不太行。
于是想到用RSA加密,是非对称的,可以前端加密后端解密。
二、前端代码与用法
1.前端是vue项目,使用时,需要先执行:
1
|
npm i jsencrypt |
把这个依赖下载到node_modules里面。
2.可以增加一个工具类文件:项目名/src/utils/commonUtil.js,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import JSEncrypt from "jsencrypt" ; export default { encodeRSA(word, keyStr) { //这个是公钥,有入参时用入参,没有入参用默认公钥 keyStr = keyStr ? keyStr : 'MIGxxxxxxxxxxxxxxxxxxxxxxxxxx' ; //创建对象 const jsRsa = new JSEncrypt(); //设置公钥 jsRsa.setPublicKey(keyStr); //返回加密后结果 return jsRsa.encrypt(word); } } |
3.然后,需要使用的地方,就可以这样用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
//引入第2步的工具类 import commonUtil from '@utils/commonUtil' //引入一个发请求的方法,这个也需要npm i import axios from 'axios' //一个发请求用的方法 export function myget(userId) { return axios.get(`/xxx/user`, { headers: { //先把参数rsa加密下,再用urlEncoder转下码,然后放header里传给后台 userId: encodeURIComponent(commonUtil.encodeRSA(userId, null )), }, }).then(res => { return res.data }) } |
这样,就把加密参数放入header里的userId里了,后台可以取出后解密。
三、后端代码与用法
1.可以先写个工具类,如下:(RSA公钥和私钥可以用这个工具类生成,然后自己记录后使用)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import javax.crypto.Cipher; import java.security.KeyFactory; import java.security.Security; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Map; import java.util.HashMap; import java.security.KeyPairGenerator; import java.security.SecureRandom; import java.security.KeyPair; public class RSAUtil { //公钥,可以写前端 public static String public_key= "MIGxxxxxx" ; //私钥,只能放后端 public static String private_key= "MIICxxxxxxxx" ; public static void main(String[] args) { //解密数据 try { //生成公钥和私钥 genKeyPair(); String publicKey = keyMap.get( 0 ); //打印出来自己记录下 System.out.println( "公钥:" + publicKey); String privateKey = keyMap.get( 1 ); //打印出来自己记录下 System.out.println( "私钥:" + privateKey); //获取到后,可以放这里,测试下能不能正确加解密 publicKey = public_key; privateKey = private_key; String orgData = "test" ; System.out.println( "原数据:" + orgData); //加密 String encryptStr =encrypt(orgData,publicKey); System.out.println( "加密结果:" + encryptStr); //解密 String decryptStr = decrypt(encryptStr,privateKey); System.out.println( "解密结果:" + decryptStr); } catch (Exception e) { e.printStackTrace(); } } /** * RSA公钥加密 * * @param str 加密字符串 * @param publicKey 公钥 * @return 密文 * @throws Exception 加密过程中的异常信息 */ public static String encrypt(String str,String publicKey) throws Exception { //base64编码的公钥 byte [] decoded = decryptBASE64(publicKey); Security.addProvider( new org.bouncycastle.jce.provider.BouncyCastleProvider()); RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance( "RSA" ).generatePublic( new X509EncodedKeySpec(decoded)); //RSA加密 Cipher cipher = Cipher.getInstance( "RSA" ); cipher.init(Cipher.ENCRYPT_MODE, pubKey); String outStr = encryptBASE64(cipher.doFinal(str.getBytes( "UTF-8" ))); return outStr; } /** * RSA私钥解密 * * @param str 加密字符串 * @param privateKey 私钥 * @return 明文 * @throws Exception 解密过程中的异常信息 */ public static String decrypt(String str, String privateKey) throws Exception { //64位解码加密后的字符串 byte [] inputByte = decryptBASE64(str); //base64编码的私钥 byte [] decoded = decryptBASE64(privateKey); Security.addProvider( new org.bouncycastle.jce.provider.BouncyCastleProvider()); 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; } //编码返回字符串 public static String encryptBASE64( byte [] key) throws Exception { return ( new BASE64Encoder()).encodeBuffer(key); } //解码返回byte public static byte [] decryptBASE64(String key) throws Exception { return ( new BASE64Decoder()).decodeBuffer(key); } /** * 密钥长度 于原文长度对应 以及越长速度越慢 */ private final static int KEY_SIZE = 1024 ; /** * 用于封装随机产生的公钥与私钥 */ private static Map<Integer, String> keyMap = new HashMap<Integer, String>(); /** * 随机生成密钥对 * @throws Exception */ public static void genKeyPair() throws Exception { // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance( "RSA" ); // 初始化密钥对生成器 keyPairGen.initialize(KEY_SIZE, new SecureRandom()); // 生成一个密钥对,保存在keyPair中 KeyPair keyPair = keyPairGen.generateKeyPair(); // 得到私钥 RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到公钥 RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); String publicKeyString = encryptBASE64(publicKey.getEncoded()); // 得到私钥字符串 String privateKeyString = encryptBASE64(privateKey.getEncoded()); // 将公钥和私钥保存到Map //0表示公钥 keyMap.put( 0 , publicKeyString); //1表示私钥 keyMap.put( 1 , privateKeyString); } } |
2.使用时,把公钥内容放入前端js,私钥内容就放后端代码里,就可以和前端联调测试了。样例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
//测试接口 @GetMapping ( "/xxx/user" ) public String myget(HttpServletRequest request) { //先用非对称算法RSA解密一下 try { //从header里获取到参数 String userId = request.getHeader( "userId" ); log.debug( "收到userId,内容为:" +userId); //这里解密,注意先用URLDecode处理了下,如果前端没有用的话,这里也不用处理 userId = RSAUtil.decrypt(URLDecoder.decode(userId, "UTF-8" ), RSAUtil.private_key); log.debug( "RSA解密成功,userId为" +userId); } catch (Exception e) { log.error( "RSA解密失败" ,e); //如果解密失败,就返回null return null ; } return "成功" ; } |
原文链接:https://blog.csdn.net/BHSZZY/article/details/129156884
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
暂无评论内容