How to Ensure Data Security in front and back API Interactions? In this article, we introduce how to deal with data encryption and decryption in Spring Boot framework. For the request encryption also only do the automatic encryption of POST request, today continue to introduce the security of GET request?
Let’s start with a simple GET request:
Cxytiandi.com/user?name=y…
First of all, we can see that the name parameter is in clear text. If security requirements are very high, we recommend that the query also use POST request. Previously, we did the encryption operation for all the parameters of POST request.
Either GET or POST can be signed
The plaintext doesn’t matter, but the point is that I’m going to copy this request into my browser and open it up, change the name to something else, and it will return the result if it actually exists. That’s the problem, the parameters have been modified, the back end can’t recognize, that’s the first problem.
The second problem is that this request can be used indefinitely, that is, if you request the address tomorrow, it can still return the result. In fact, this also needs to be controlled, of course, there are many ways to control, today we will introduce a relatively simple way to control.
The first way
The parameters are concatenated into a string in alphabetical order. Then the parameters are concatenated into a string. Finally, MD5 or SHA encryption is used to obtain an encrypted signature, which is sent to the backend for verification.
Such as:
name=yinjihuan&sign=MD5(name=yinjihuan+key)
At the back end, we can conduct unified verification in the filter to obtain the value of parameter sign and all parameters of the request. At the same time, we can generate a new sign in the same way as the front-end generates sign, and compare the two signs. If they are equal, it proves that the parameters have not been tampered.
In order to prevent a request has been used for many times, we usually sign in again with the timestamp request that point, the server side will judge lag, if in 10 minutes to let it continue, of course, this ten minutes you can to adjust, longer way mainly to the client and the server time is not the same problem, Of course, this situation cannot be completely avoided.
The second way
The second method is relatively simple, because we have talked about the requested data encryption and decryption before, since we have the encryption key and encryption algorithm, in fact, we can use our encryption algorithm to encrypt the content of the signature, the above md5 method is not very secure, MD5 can be cracked.
And because I’m using AXIos to request data, I can use the request interceptor to sign the request uniformly before the request is made, rather than processing it individually at each location.
When using a GET request, we do the following:
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
Copy the code
Then in the request interceptor, we can obtain all the parameter information of the current request through Params. Here, we do not adopt the way of splicing, directly add a signTime to Params, and then encrypt the whole Params to get a sign, which is passed to the background through the request header.
For example, {name:”yjh”,signTime:19210212121212}, and the signature is {name:”yjh”,signTime:19210212121212}.
/ / add request interceptor axios. Interceptors. Request. Use (function(config) {// What to do before sending the requestif (config.method == "get"){
var newParams = config.params;
console.log(newParams);
if (newParams == undefined) {
newParams = new Object();
}
newParams.signTime = new Date().getTime();
config.headers.sign = EncryptData(JSON.stringify(newParams));
console.log(JSON.stringify(config));
}
if (config.method == "post"){
var newParams = new Object();
newParams.signTime = new Date().getTime();
config.headers.sign = EncryptData(JSON.stringify(newParams));
}
return config;
}, function(error) {// What do I do about the request errorreturn Promise.reject(error);
});
Copy the code
The backend can perform signature verification in the filter as follows:
<br> ** sign= encryption ({parameter: value, parameter 2: Value of 2. Timestamp signTime: signature}) * @ author yinjihuan @ the about http://cxytiandi.com/about * * * * / public class SignAuthFilter implements Filter { private EncryptProperties encryptProperties; @Override public void init(FilterConfig filterConfig) throws ServletException { ServletContext context = filterConfig.getServletContext(); ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context); encryptProperties = ctx.getBean(EncryptProperties.class); } @SuppressWarnings("unchecked")
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
if (req.getMethod().equals("OPTIONS")) {
chain.doFilter(request, response);
return;
}
resp.setCharacterEncoding("UTF-8");
String sign = req.getHeader("sign");
if(! StringUtils.hasText(sign)) { PrintWriterprint = resp.getWriter();
print.write("Illegal request: Missing signature information");
return;
}
try {
String decryptBody = AesEncryptUtils.aesDecrypt(sign, encryptProperties.getKey());
Map<String, Object> signInfo = JsonUtils.getMapper().readValue(decryptBody, Map.class);
Long signTime = (Long) signInfo.get("signTime"); // If the difference between the signature time and the server time is more than 10 minutes, the request is considered expired. This time can be configuredif ((System.currentTimeMillis() - signTime) > encryptProperties.getSignExpireTime() * 60000) {
PrintWriter print = resp.getWriter();
print.write("Illegal request: Expired");
return; } // POST requests handle only time // GET requests handle parameters and timeif(req.getMethod().equals(HttpMethod.GET.name())) {
Set<String> paramsSet = signInfo.keySet();
for (String key : paramsSet) {
if (!"signTime".equals(key)) {
String signValue = signInfo.get(key).toString();
String reqValue = req.getParameter(key).toString();
if(! signValue.equals(reqValue)) { PrintWriterprint = resp.getWriter();
print.write("Illegal request: Parameter tampered with");
return;
}
}
}
}
} catch (Exception e) {
PrintWriter print = resp.getWriter();
print.write("Illegal request :" + e.getMessage());
return;
}
chain.doFilter(request, response);
}
@Override
public void destroy() {}}Copy the code
First of all, we will determine the signature information, not intercept off, and then decrypt operation, get the signature time, determine the period of validity, and then based on the parameters obtained from the decryption information, circulation and comparison of parameters of the current request, as long as there is a right, it’s parameters has been tampered with, this way is simple, I do is converted to the string to compare to the judgment of value, Not sure if there is a problem with some particular data types, you can change it yourself.
The verification code is also wrapped in my spring-boot-starter-encrypt (welcome Star) : github.com/yinjihuan/s…
Just configure the filter:
/** * Register signature verification filter * @return
*/
@Bean
public FilterRegistrationBean signAuthFilter() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new SignAuthFilter());
registrationBean.setUrlPatterns(Arrays.asList("/rest/*"));
return registrationBean;
}
Copy the code
You may not be able to use the above code, I personally think there is no need to copy my code to experiment, understand the idea is your best choice. Simply share, not spray…
Recommend “Spring Boot + Vue front and rear end separation actual combat” take you to navigate the ocean of front and rear end separation.