1. Reasons for demand
As shown in the figure, if the address is exposed, anyone who gets the address can directly send the request, but the front-end sending request must be realized through http. Therefore, the address will be exposed and interested people will get the address. Therefore, it is necessary to add a sign signature. The way to generate the signature is unknown to others, This will ensure that others can't use the address
2 encryption principle
When the client sends a packet to the server, it will generate a signature a based on the packet and send it together. When the server receives the packet, it will also generate a signature B based on the packet, and compare the signatures A and B. if the two are the same, it is considered that the packet is indeed sent legally by the client, and the server will respond to the request. If the signatures are inconsistent, Indicates that the data of the packet has been temporarily tampered with
The most important thing in the whole process is to implement encryption based on data packets. Therefore, the sign signature is not used as any field, but based on certain encryption rules. This encryption rule focuses on confidential data both on the client and the server
3 signature timeliness
The sign signature should be time-effective. Otherwise, if someone intercepts a single request and sends the request to the server 100 times, there will be trouble. For example, if the user wanted to send a paid prop, he was intercepted and sent the request repeatedly, which will become asking the client to send 100 gifts, and the user's money will be gone.
There are two ways to achieve timeliness:
-
After the user logs in, the server issues the token to which the user belongs. Each user is different. The token is used as the encryption secret key in the signature generation rules. Because the token has a validity period, the generated signature can also be time-effective. However, in this way, two-layer encryption must be done. The token returned after login must be encrypted and cannot be returned in plaintext, and then the data packet can be encrypted normally
-
Make the request carry a timestamp. The request response time and timestamp must not exceed XX seconds, which is equivalent to setting the expiration time for the signature. Assuming that the expiration time is set to 2 seconds, the signature expires just after the request is intercepted and before it is packaged and sent, which realizes timeliness
If you encounter a malicious request attack, you need to use a dynamic filter, which is another solution. It is not the same thing as the signature aging performance
4. Selective encryption (dynamic signature verification)
Not all interfaces need to be encrypted, such as the number of people in the room and the gift data. There is no need to encrypt these. Only very important functions, such as payment and recharge, need to be encrypted
To implement encryption, you need to generate a signature and complete the comparison before the request reaches the controller, so you need to set an interceptor
5 implementation mode
5.1 create a simple interceptor
Write the interceptor under the common module
First create an interceptor
Then configure the interceptor in the spring configuration class
@Configuration public class DefaultConfig implements WebMvcConfigurer { Logger logger = LoggerFactory.getLogger(DefaultConfig.class); @Resource private AuthInterceptor authInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authInterceptor).addPathPatterns("/**") .excludePathPatterns("/login/**"); } }
5.2 sort out the data intercepted by the interceptor
Now, if the front end requests the interface directly, it will be intercepted by the interceptor
The interceptor can identify the interface and specific method to be accessed by the request, and can also see whether there are annotations on this method and what annotations there are. Then we only need to customize an annotation and put it on the method to be encrypted. When the filter finds that the front-end request wants to access the method with this annotation, it will intercept it, so as to realize dynamic signature verification, Only important methods are verified
5.3 user defined annotation
Customize an annotation in the public module, and set the life cycle, annotation type and a boolean variable
@Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Auth { boolean isCheck() default true; }
As shown in the figure, this annotation is placed on the method that needs to be encrypted to achieve the purpose of fixed-point interception
5.4 complete the preparation of filter
5.4.1 annotation of acquisition method
The filter can obtain the annotation of the requested method based on the method shown in the figure
5.4.2 user defined encryption method
- Extension: sorting by TreeMap
The code is shown in the figure
The effect is shown in the figure
As long as the encryption method is complex enough, it is difficult for others to obtain and crack it. There is no fixed saying
For example, we set an encryption method, first sort the attributes in the packet according to A-Z or Z-A, and then convert them into strings. Using TreeMap, we can realize A-Z or Z-A sorting
Then take out the ordered attributes one by one and spell them into a string, which is similar to the effect in the figure below. In the figure, C is an array, so there are multiple values, and the values are separated by commas
The code is as follows. After splicing the attributes, finally splice the token sent to the user by the server after the user logs in. In this way, when a signature mismatch is found, the token can be recorded and traced back to the user who sent false data. Then, the user can be sealed or the alarm can be sent to the network police for processing
Finally, encrypt the string sb and compare it with the signature in the packet sent by the front end. If the comparison is correct, it will be released
5.4.3 filter code
The overall code is as follows
@Component public class AuthInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //Gets the annotation on the requested method Auth methodAnnotation = ((HandlerMethod) handler).getMethodAnnotation(Auth.class); //If the @ Auth annotation can be obtained and the isCheck of the annotation is true, intercept and verify it if(methodAnnotation != null && methodAnnotation.isCheck()){ //verification Map<String, String[]> parameterMap = request.getParameterMap(); TreeMap<String, String[]> treeMap = new TreeMap<>(parameterMap); StringBuilder sb = new StringBuilder(); treeMap.forEach((s, strings) -> { if(!s.equals("sign")){ sb.append(s); sb.append("="); sb.append(strings); sb.append("&"); } }); sb.append("token="+"asdasdasdasdasdas"); //This step: implement MD5 encryption with the help of hutool tool class to obtain the signature A of the server //Get the signature B passed by the front end String sign = request.getParameter("sign"); //This step: compare the signatures of the front end and the server before releasing the request } return false; } }