preface
The development mode of front and back end separation, we take the interface as the standard to promote, define the interface, develop their own functions, and finally carry out joint integration. Regardless of the development of native APP, WebAPP or PC software, as long as the mode of front and back end separation, it is inevitable to call the interface provided by the back end for business interaction.
Web pages or apps that simply grab the package and know exactly what data the request is getting are a boon to crawler engineers who can easily grab your data.
Data security is very important, especially user-related information, a little careless will be stolen by criminals, so we should pay great attention to this, do not allow careless.
How to ensure the security of the data during API calls?
- Use HTTPS for communication
- Request signature to prevent parameter tampering
- An authentication mechanism that validates each request
- SSL pinning is used in apps to prevent package capture
- All requests and responses are encrypted and decrypted
- And so on…….
All requests and responses are encrypted and decrypted
Project, there are many kinds of when you do, the more means higher security, today I told everyone to introduce encryption on all requests and responses for operation, even can be caught, even if the interface can call me, but I returned data is encrypted, as long as the encryption algorithm is safe enough, you got my encrypted content has no influence on me.
You can’t have every developer pay attention to this, it would be a hassle to have every developer pay attention to this, you have to manually call the encryption method when the data is returned, and you have to call the decryption method when the data is received.
To do this, I packaged a Starter based on Spring Boot with the AES encryption algorithm built in. GitHub address:
Github.com/yinjihuan/s…
Add @enableencrypt to the bootstrap class to enable encryption and decryption:
@EnableEncrypt @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); }}Copy the code
Add the encrypted key configuration:
spring.encrypt.key=abcdef0123456789
spring.encrypt.debug=false
Copy the code
- Spring.encrypt. key: encryption key, which must be 16 bits
- Spring.encrypt. debug: Indicates whether to enable the debugging mode. The default value is false. If the debugging mode is true, encryption and decryption are not enabled
For the sake of generality, encryption and decryption will not be performed on all requests, with annotation-based controls
If the response data needs to be encrypted, just add the @encrypt annotation to the Controller’s method.
@Encrypt
@GetMapping("/list")
public Response queryNews(String city) {
return Response.ok(city);
}
Copy the code
When we access the /list interface, the data returned is in the base64 encoded format after encryption.
Another operation is the data submitted in the previous section, which can be divided into two cases. One is get request, which is not processed for the moment, but will be considered later. Currently, only POST request is processed, which is submitted in JSON format. That is to say, the background needs to receive data using @requestBody, and we need to add @decrypt to any operations that need Decrypt.
@Decrypt
@PostMapping("/save")
public Response savePageLog(@RequestBody PageLogParam logParam, HttpServletRequest request) {
pageLogService.save(logParam);
return Response.ok();
}
Copy the code
After the @Decrypt annotation, the data submitted by the front end needs to be encrypted according to the AES algorithm, and then sent to the back end, where it is automatically decrypted and mapped to the parameter object.
All of the above is the back-end code. If you use the front end, we will use JS. Of course, you can also use other languages to do this, if it is a native Android app, you will also use Java code.
The front end needs to do two things:
- Unified processing of data in response to decryption prior to rendering to the page
- When data is sent with a POST request, it is uniformly encrypted
Js file. See aes.js,crypto-js.js, and pad- zeropAdding. Js in encrypt on GitHub
We use AXIOS as the framework for requesting data and AXIOS’s interceptor to handle encryption and decryption operations uniformly
First of all, we still need to encapsulate a JS encryption and decryption class. It needs to be noted that the encryption key needs to be matched with the background, otherwise it can not decrypt each other. The code is as follows:
var key = CryptoJS.enc.Latin1.parse('abcdef0123456789');
var iv = CryptoJS.enc.Latin1.parse('abcdef0123456789'); / / encryptionfunction EncryptData(data) {
var srcs = CryptoJS.enc.Utf8.parse(data);
var encrypted = CryptoJS.AES.encrypt(srcs, key, {
mode : CryptoJS.mode.ECB,
padding : CryptoJS.pad.Pkcs7
});
returnencrypted.toString(); } / / decryptionfunction DecryptData(data) {
var stime = new Date().getTime();
var decrypt = CryptoJS.AES.decrypt(data, key, {
mode : CryptoJS.mode.ECB,
padding : CryptoJS.pad.Pkcs7
});
var result = JSON.parse(CryptoJS.enc.Utf8.stringify(decrypt).toString());
var etime = new Date().getTime();
console.log("DecryptData Time:" + (etime - stime));
return result;
}
Copy the code
Uniform handling code in axios interceptor:
/ / add request interceptor axios. Interceptors. Request. Use (function(config) {// Encrypt all posts, must be JSON data submission, do not support formsif (config.method == "post") {
config.data = EncryptData(JSON.stringify(config.data));
}
return config;
}, function (error) {
returnPromise.reject(error); }); / / add the response interceptor axios. Interceptors. Response. Use (function(Response) {// The back end returns a string indicating that a decryption operation is requiredif(typeof(response.data) == "string"){
response.data = DecryptData(response.data);
}
return response;
}, function (error) {
return Promise.reject(error);
});
Copy the code
So far, we have done an encryption operation for the whole communication between the front and back end. As long as the encrypted key is not leaked, it is useless for others to get your data. The problem is how to ensure that the key is not leaked?
The security of the server side is higher, and it can be stored in the database or configuration file. After all, on our own server, the most dangerous thing is actually the front end. App is ok, it can be packaged, but it needs to prevent decompilation and other problems.
If it is webApp can rely on JS encryption to achieve, I will give you a dynamic access to the encryption key, but the implementation is more complex, we do not code, just talk about ideas:
Encryption algorithms include symmetric encryption and asymmetric encryption. AES is symmetric encryption and RSA is asymmetric encryption. AES is used to encrypt data because of its high efficiency. RSA runs slowly and can be used for signature operations.
We can use these two algorithms to complement each other to ensure security, use RSA to encrypt AES secret keys, and use AES to encrypt data. The two algorithms complement each other.
HTTPS is slower than HTTP because the client and server need to securely negotiate a symmetric encryption algorithm. All that remains is for both sides to use this symmetric encryption algorithm to encrypt and decrypt the communication.
- The client starts and sends a request to the server. The server uses RSA algorithm to generate a pair of public and private keys, which we call pubkey1 and prikey1 for short, and returns the public key pubkey1 to the client.
- After the client gets the public key Pubkey1 returned by the server, it uses RSA algorithm to generate a pair of public key and private key, which is called Pubkey2 and prikey2 for short, and encrypts public key Pubkey2 through public key Pubkey1 and transmits the encryption to the server.
- At this point, the server receives the ciphertext transmitted by the client and decrypts it with the private key Prikey1. Because the data is encrypted with the public key Pubkey1, the public key pubkey2 generated by the client can be obtained through decryption
- After generating the key, we use the public key Pubkey2 to encrypt it and return it to the client, because only the client has the private key prikey2 corresponding to Pubkey2. Only the client can decrypt the data. After the client gets the data, it uses PriKEY2 to decrypt the data and obtain the ENCRYPTION key of AES. Finally, it uses the encryption key to encrypt the data transmission.
Spring – the boot – starter – encrypt principle
Finally, we will briefly introduce the principle of spring-boot-starter-encrypt, but also to let you understand why spring Boot is so convenient, only a simple configuration can achieve a lot of functions.
The @enableENCRYPT annotation on the bootstrap class is used to enable functionality that imports the auto-configuration class via @import
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({EncryptAutoConfiguration.class})
public @interface EnableEncrypt {
}
Copy the code
EncryptAutoConfiguration configures request and response processing classes using RequestBodyAdvice and ResponseBodyAdvice in Spring, which is convenient to statistically process requests. If you want to wrap it at a lower level, you have to do it from the servlet.
@Configuration @Component @EnableAutoConfiguration @EnableConfigurationProperties(EncryptProperties.class) public class EncryptAutoConfiguration {/** * Configures the request to decrypt * @return
*/
@Bean
public EncryptResponseBodyAdvice encryptResponseBodyAdvice() {
returnnew EncryptResponseBodyAdvice(); } /** * configure request encryption * @return
*/
@Bean
public EncryptRequestBodyAdvice encryptRequestBodyAdvice() {
returnnew EncryptRequestBodyAdvice(); }}Copy the code
RequestBodyAdvice and ResponseBodyAdvice can be used to handle a request response.
For more technology sharing, please pay attention to wechat public number: Ape World