Our overall design for the message service is that after the client connects to the server, it initiates identity authentication, carries the application code and key, and hash encrypts the key. After the server passes the authentication, it establishes a long connection.
For the long connection, we think it is secure. Malicious users cannot directly send a forged message to the long connection channel, so it is not necessary to sign and verify each message, which improves the performance. But there is also a small loophole. Unauthenticated applications are prevented. How to deal with authenticated applications if they operate beyond their authority?
For example, the logistics system LMS is connected to the TMS system of two carriers. If carrier A sends A message for confirmation, but the application code carried in the message is B, it is unlikely that this will happen, but there are still some hidden dangers..
The key to this problem is that we identify the application and use the application code carried in the message, rather than the application code saved in the connection after successful login authentication.
There are two schemes: one is to obtain the application identification value saved when the login is successful from the connection channel where the application code is used; the other is to verify whether the application code carried by the client message is consistent with the application code in the channel in the data verification phase.
Under comprehensive consideration, scheme 1 obtains the application code from the channel. In many methods of using application code, it needs to obtain the channel object additionally, which is more troublesome; Scheme 2 is more convenient and only a small change is needed, so we adopt scheme 2
Relevant modifications are as follows:
As long as the server needs to verify whether the application code is consistent with the message channel, it cannot be put into the basic data verification process shared by the client and the server, but into the MessageHandler of the server. In the application verification phase, compare whether the application code carried in the message is consistent with the application code corresponding to the channel. If it is inconsistent, An exception is thrown. Whether there is a traceable message sent by others, and whether there is an error in the application log at the same time.
/** * Verification application * * @param publishAppCode Message application code * @param appCode Channel application code */ protected void validateAppCode(String publishAppCode,String appCode) { //In this place, the appCode needs to be blank. For example, in the login operation, the appCode of the channel does not exist if(appCode!=null && !appCode.equals(publishAppCode)){ log.error("The application ID is inconsistent with the message channel,Application identification:{},Message channel{}",publishAppCode,appCode); throw new MessageException("S201", "The application ID is inconsistent with the message channel"); } try { ApiApp app =apiAppService.getByCode(publishAppCode); if(app.getStatus().equals(StatusEnum.DEAD.name())){ throw new MessageException("S203", "App disabled"); } }catch (Exception ex){ throw new MessageException("S202", "Invalid app ID"); } }
How to obtain the application ID of the channel? We transform the global container and add a new method to obtain appCode with channel object
/** * Obtain the corresponding channel according to the application code * @param channel */ public static String getAppCode(Channel channel) { //Read user ID from channel attribute AttributeKey<String> appCodeAttribute=AttributeKey.valueOf(APP_CODE_KEY); return channel.attr(appCodeAttribute).get(); }
Then, in the request / response message processor, the global container method is invoked to get appCode to the framework validation link.
/** * Message processing * * @param message news * @param channel passageway */ public void handleMessage(RequestMessage requestMessage, Channel channel) { // Log message requests apiMessageLogService.createRequestPart(requestMessage); //Validation framework String appCode = MessageServerHolder.getAppCode(channel); validateFramework(requestMessage,appCode); //The request message status is set to no need to send by default apiMessageLogService.updateStatus(MessageStatusEnum.NOT_TO_REQUEST.name(),requestMessage.getId()); //Special treatment messageOperation(requestMessage, channel); //Send response to message sender sendResponse(requestMessage, channel); //Message processing (copy and forward) if(isNeedRepost()){ repostMessage(requestMessage.getTopic(),requestMessage.getContent()); } }
After the transformation is completed, conduct the test, deliberately create an inconsistent data, and the server will print the error log:
The application ID is inconsistent with the message channel,Application identification: ABC,Message channel SCS
At the same time, respond to an error message from the client
{"errorCode":"500","errorMessage":"The application ID is inconsistent with the message channel", "id":"1489404728953479170","messageType":"RESPONSE","publishAppCode":"MessageServer", "publishTime":"2022-02-04 09:05:33","requestMessageId":"1489404726461988866","result":"ERROR", "topic":"framework.error.response"}