Implementation of interface authentication function

1. Background

With the development of the system, the monolithic application gradually evolved into a microservice architecture. After the system is micro-serviced, there will be calls among several micro-services. The services implemented in the same department will be called internally, and the general risk is controllable. However, if the service is provided to other departments for use, without understanding the other party’s usage scenarios, interface calls QPS, etc., if the other party’s interface calls are too large, it will affect the entire caller using the service, and the security of the interface will also be affected. risky. In this case, each microservice needs to authenticate the caller.

The basic authentication dimensions are:

  • Application authentication: When the other party calls an interface of our service, it needs to pass the other party's user ID, such as appKey. Let us see if this appKey has the authorization call permission, it does not directly return the failure; if authorized, the result can be returned normally;
  • Interface authentication: More fine-grained authentication. After the application authentication is passed, an interface needs to be authenticated. For example, team A wants to call the order service, we only want to develop the authority of the order query interface, and the interface related to the order refund and other operations can deny access to the other party. Common interface authentication includes call authentication between RPC interfaces and HTTP interface call authentication.

2. Demand analysis

1. Basic realization plan

First of all, the most basic implementation scheme we can think of:

  • The caller applies for access permission. After the server is authorized, the password corresponding to the caller will be generated and stored in the component with storage function such as DB/cache, appKey <—> password
  • When calling the interface, the caller needs to pass the appKey and password together as parameters;
  • After receiving the request, the server takes out the parameters appKey and password password in the request, and obtains the corresponding password from the DB/cache according to the apppKey, and judges whether the password stored by the server is consistent with the password passed by the other party. If they are inconsistent, the access is denied.

2. Replay attack

The above process is the simplest implementation, but there is a risk of replay attacks.

Replay attacks refer to:

Replay Attacks (Replay Attacks), also known as replay attacks and playback attacks, refer to the attacker sending a packet that the destination host has received to achieve the purpose of deceiving the system. It is mainly used in the identity authentication process to destroy the correctness of the authentication. The replay attack can be carried out by the initiator or the enemy who intercepts and retransmits the data. The attacker uses network monitoring or other methods to steal the authentication credentials, and then resend it to the authentication server . Replay attacks can occur during any network pass, and it is one of the common attack methods used by hackers in the computer world .

Note: from Baidu Encyclopedia

Popular explanation: the attacker uses network monitoring or other methods to intercept the message sent by A to B, and sends the message encrypted by A to B, making B mistakenly believe that the intruder is A, and then host B pretends to be A The attacker sends a message that should be sent to A.

3. Optimization method

(1) Optimization method 1: Data encryption

The caller passes the caller’s identity information and password in plain text. This process will be intercepted by a third party to obtain the appKey and password. The third party can pretend to be an authenticated caller based on the obtained information to call the service provider. The interface information poses a threat to the stability and security of the server's service. This is the "replay attack".

Solution:

Encrypt the data.

  • The caller puts the called interface name + appKey + password together, encrypts it with an encryption algorithm to generate a token value, and then splices the token value to the original calling url and sends it to the server, such as:http://localhost:8080/user?getUserInfo?userId=1234&appKey=abc&token=dasadjij21oijiooodsadaodjaosnd

  • After the server receives the request sent by the caller, it parses and obtains the appKey and token values, and obtains the corresponding password value from the server storage according to the appKey, and then uses the same encryption algorithm to generate the token value of the server: token_s, and call with token_s The token values ​​of the parties are compared. If they are the same, access is allowed; if they are not the same, access is denied.

[External link image transfer failed. The source site may have an anti-leech link mechanism. It is recommended to save the image and upload it directly (img-bfnGoFyi-1575984360956)(/Users/wanggenshen/Library/Application%20Support/typora-user-images/image- 20191204113153975.png)]

(Image source: Geekbang Time https://time.geekbang.org/column/article/171760)

(2) Optimization method two: data encryption + random number

The above method is more than sufficient for internal systems that do not require high security. However, this design still has the risk of replay attacks: since the generated token value is fixed, the attacker can spend a certain amount of time to crack. Therefore, it is necessary to continue to optimize the token generation algorithm and generate dynamic tokens to avoid this risk.

Solution:

In order to generate a dynamic token, a random number is introduced, and the random number is also encrypted during encryption, so that the token generated each time is dynamically changed. Generally, timestamps are used as random numbers. The advantage of using timestamps as random numbers is that the receiver can also verify whether the token has expired after parsing the timestamp. For example, the timestamp is a timestamp corresponding to a year ago, so access is naturally not allowed;

  • The caller encrypts the url + appKey + password + timestamp, and generates a dynamic token, which is spliced ​​on the url, and the timestamp is spliced ​​at the same time, and sent to the server;

  • After the server receives the request,

    • First parse out the appKey, password, timestamp, and token;

    • Then check whether the timestamp is within the time window, such as 1 hour; if the check fails, the token is considered expired and the access is denied directly, and the next step is passed;

    • Then according to the appKey to query the corresponding passwrod_s, use the same encryption algorithm to

      url + appKey + passwrod_s + timestamp for encryption to generate new token_s, compare

      token and token_s: the same, access is allowed; not the same; access is denied;

The schematic diagram is as follows:

[External link image transfer failed. The source site may have an anti-leech link mechanism. It is recommended to save the image and upload it directly (img-xV425cOz-1575984360957)(/Users/wanggenshen/Library/Application%20Support/typora-user-images/image- 20191204135912522.png)]

(Image source: Geekbang Time https://time.geekbang.org/column/article/171760)

4. Timing diagram

The above sequence diagram is as follows:

[External link image transfer failed. The origin site may have an anti-leech link mechanism. It is recommended to save the image and upload it directly (img-jErD4PQb-1575984360959)(/Users/wanggenshen/Library/Application%20Support/typora-user-images/image- 20191210212456359.png)]

Three, code actual combat

The list of function points obtained by the above method is as follows:

  • (1) Concatenate URL, appKey, password, and timestamp into one string;
  • (2) Encrypt the string through an encryption algorithm to generate a token;
  • (3) Splicing token, appKey, and timestamp into the URL to form a new URL;
  • (4) Parse the URL to get token, appKey, timestamp and other information;
  • (5) Take out appKey and corresponding password from storage;
  • (6) Determine whether the token is expired or invalid according to the timestamp;
  • (7) Verify whether the two tokens match;

After analysis, it can be known that 3 functions are designed:

  • Url operation related, including Url splicing parameters and Url parsing;
  • Token operation related, including token generation, judgment of token expiration, and judgment of whether the token matches;
  • appKey storage and query;

So divided by domain model, there are a total of 3 models, corresponding to 3 categories, as follows:

(1) Url not only includes HTTP interface url requests, but also RPC interface requests, so it is abstractly encapsulated into the ApiRequest class:

(2) Token design:

AuthToken

(3) AppKey query, for abstraction, provides an interface:

(4) After defining the design of the domain model, you need to assemble these classes and provide entrances:

public interface ApiAuthencator {
    
    
    void auth(String url);
    void auth(ApiRequest apiRequest);
}

(5) Test

For better test results, the InvokerController class is provided to simulate the token generation, url splicing, triggering server authentication and other actions when the client calls.

See the complete code : complete code


Reference: Geek Time "The Beauty of Design Patterns"

Guess you like

Origin blog.csdn.net/noaman_wgs/article/details/103483349