0%

使用RSA加密http请求中的数据

概念

Http协议报文明文传输,如果被恶意分子抓包,未经加密的数据便一览无余。

为了数据的安全传输,可以采用对称加密和非对称加密算法保驾护航。

过程

以客户端到服务器为例。

在客户端向服务器发送数据之前,服务器将自己通过RSA算法产生的公钥交给客户端。在发送数据时,客户端用得到的公钥加密要传输的数据,加密完成后传输密文给服务器,服务器收到数据后首先使用之前产生的私钥进行解密,解密成功后得到数据。

这个过程服务器的私钥从未传输,所以恶意分子无法通过窃听获得原始的数据。

具体实现

以Spring + Thyme Leaf + Vue.js + axios为例。

产生秘钥

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Component
@Scope("singleton")
public class CipherUtil {
private final PublicKey publicKey;
private final Cipher decryptCipher;

public CipherUtil() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
this.publicKey = keyPair.getPublic();
this.decryptCipher = Cipher.getInstance("RSA");
decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
}

public String getPublicKey() {
return Base64.getEncoder().encodeToString(publicKey.getEncoded());
}

public String decrypt(String content) throws BadPaddingException, IllegalBlockSizeException {
return new String(decryptCipher.doFinal(Base64.getDecoder().decode(content)));
}
}

将服务器端产生的秘钥交给客户端

Controller

1
2
3
4
5
@GetMapping("/")
public String home(Model model) {
model.addAttribute("publicKey", cipherUtil.getPublicKey());
return "home";
}

HTML

1
2
3
<script th:inline="javascript">
const publicKey = [[${publicKey}]];
</script>

客户端使用公钥加密

拦截表单提交

1
2
3
<form method="post" name="form" action="/submit" v-on:submit.prevent="upload">
.............
<form>

对数据加密后提交表单

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
new Vue({
el: '#app',
data: {
xx: '',
yy: ''
},
methods: {
upload() {
const encryptor = new JSEncrypt();
encryptor.setPublicKey(publicKey);

const formData = new FormData();
formData.append("xx", encryptor.encrypt(this.xx));
formData.append("yy", encryptor.encrypt(this.yy));
formData.append("zz", this.action);

axios({
method: "post",
url: "/submit",
headers: {
"Content-Type": "multipart/form-data"
},
data: formData
}).then((res) => {
console.log(res);
});
}
}
});

服务端收到数据后解密

1
2
3
4
5
6
7
8
@PostMapping("/submit")
@ResponseBody
public String submit(@RequestParam("action") String value, @RequestParam("id") String id, @RequestParam("password") String password) {
id = cipherUtil.decrypt(id);
password = cipherUtil.decrypt(password);
/////////////////// operations here /////////////////////////
return "hhh";
}