Interviewer: how to design an external security interface?

Posted by coppercoins on Wed, 19 Jan 2022 13:00:47 +0100

Hello, I'm brother dog. Recently, in connection with business parties, I need to give them an interface to call. This interface design involving external calls generally involves many aspects, such as:

  • Signature is used to prevent data tampering
  • Information encryption and key management
  • Build oauth2 0 authentication authorization
  • Use Token Mode
  • Build a gateway to realize blacklist and whitelist

01 build API open platform in token mode

The following is the interface call flow chart of this scheme:

Scheme design:

  1. The third-party organization applies for an appId and obtains the accessToken through the appId. Each time it requests to obtain the accessToken, the old accessToken must be deleted
  2. The third-party organization needs to add the accessToken parameter to request data. Before the business processing center executes business each time, go to the dba persistence layer to check whether the accessToken exists (you can put the accessToken in redis, which has the effect of expiration time). The existence indicates that the organization is legal and can request business data without logging in. The absence indicates that this organization is illegal and does not return business data.
  3. Benefits: stateless design. Every request is guaranteed to be the request of the organization saved in our persistence layer. If someone steals our accessToken, they can re apply for a new token

02 based on oauth2 0 protocol mode

The principle of third-party authorization is the same as that of token 1:

  1. Suppose I am service provider a, I have a development interface, and external organization B must apply for its own appid (Organization B id) to request the interface of A
  2. When B wants to call the A interface to check A user's information, it needs the corresponding user authorization. Tell A that I am willing to agree to tell b my information, and A will produce an authorization token to B.
  3. B uses the token to obtain the information of a user.

Overall processing flow of joint wechat login:

  1. The user agrees to the authorization and obtains the code
  2. Exchange code for web access authorization_ token
  3. Through access_ Get user openId with token
  4. Get user information through openId

03 information encryption and key management

  • One way hash encryption
  • Symmetric encryption
  • Asymmetric encryption
  • Security key management

3.1 one way hash encryption

Hash is the extraction of information. Usually, its length is much smaller than that of information, and it is a fixed length. The hash with strong encryption must be irreversible, which means that no part of the original information can be deduced through the hash result. Any change in input information, even if only one bit, will lead to significant changes in hash results, which is called avalanche effect. Hashing should also be conflict proof, that is, two pieces of information with the same hash result cannot be found. Hash results with these characteristics can be used to verify whether the information has been modified.

One way hash function is generally used to generate message digest, key encryption, etc. common are:

  1. MD5 (Message Digest Algorithm 5): it is a one-way hash algorithm developed by RSA data security company. It is non reversible. The same plaintext generates the same ciphertext.
  2. SHA (Secure Hash Algorithm): it can generate a 160 bit value for data of any length;

Comparison between SHA-1 and MD5

Because both are derived from MD4, SHA-1 and MD5 are very similar to each other. Accordingly, their strength and other characteristics are similar, but there are the following differences:

  • Security against forced provisioning: the most significant and important difference is that the SHA-1 digest is 32 bits longer than the MD5 digest. Using the forced technology, the difficulty of generating any message so that its summary is equal to the given message summary is 2128 for MD5 and 2160 for SHA-1. In this way, SHA-1 has greater strength against forced attacks.
  • Security of Cryptanalysis: due to the design of MD5, SHA-1 is vulnerable to cryptanalysis attacks.
  • Speed: on the same hardware, SHA-1 runs slower than MD5.
  1. Features: avalanche effect, fixed length output and irreversible.
  2. The function is to ensure the integrity of data.
  3. Encryption algorithms: md5 (standard key length 128 bits), sha1 (standard key length 160 bits), md4, CRC-32
  4. Encryption tools: md5sum, sha1sum, OpenSSL, dgst.
  5. Calculate the hash value of a file, for example: md5sum / shalsum filename, OpenSSL, dgst – md5/-sha

3.2 symmetric encryption

Secret key: the same key is used for encryption and decryption, two-way guarantee of data confidentiality, high encryption efficiency, suitable for encrypting large data and large files, and low encryption strength (compared with asymmetric encryption)

Advantages and disadvantages of symmetric encryption

Advantages: compared with public key encryption, the operation speed is fast.

Disadvantages: it cannot be used as authentication, and it is difficult to issue keys

DES

It is a symmetric encryption algorithm. In the process of encryption and decryption, the key length must be a multiple of 8

public class DES {
 public DES() {
 }
 
 // test
 public static void main(String args[]) throws Exception {
  // Content to be encrypted
  String str = "123456";
  // Password, if the length is a multiple of 8, the key can be set at will
  String password = "12345678";
  byte[] encrypt = encrypt(str.getBytes(), password);
  System.out.println("Before encryption:" +str);
  System.out.println("After encryption:" + new String(encrypt));
  // decrypt
  byte[] decrypt = decrypt(encrypt, password);
  System.out.println("After decryption:" + new String(decrypt));
 }
 
 /**
  * encryption
  * 
  * @param datasource
  *            byte[]
  * @param password
  *            String
  * @return byte[]
  */
 public static byte[] encrypt(byte[] datasource, String password) {
  try {
   SecureRandom random = new SecureRandom();
   DESKeySpec desKey = new DESKeySpec(password.getBytes());
   // Create a key factory and use it to convert DESKeySpec to
   SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
   SecretKey securekey = keyFactory.generateSecret(desKey);
   // Cipher object actually completes the encryption operation
   Cipher cipher = Cipher.getInstance("DES");
   // Initialize Cipher object with key, ENCRYPT_MODE is a constant used to initialize Cipher to encryption mode
   cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
   // Now get the data and encrypt it
   // Formal encryption operation
   return cipher.doFinal(datasource); // Encrypt or decrypt data as a single part operation, or end a multi part operation
  } catch (Throwable e) {
   e.printStackTrace();
  }
  return null;
 }
 
 /**
  * decrypt
  * 
  * @param src
  *            byte[]
  * @param password
  *            String
  * @return byte[]
  * @throws Exception
  */
 public static byte[] decrypt(byte[] src, String password) throws Exception {
  // DES algorithm requires a trusted random number source
  SecureRandom random = new SecureRandom();
  // Create a DESKeySpec object
  DESKeySpec desKey = new DESKeySpec(password.getBytes());
  // Create a key factory
  SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// Returns the that implements the specified transformation
                   // Cipher
                   // object
  // Convert the DESKeySpec object to a SecretKey object
  SecretKey securekey = keyFactory.generateSecret(desKey);
  // The Cipher object actually completes the decryption operation
  Cipher cipher = Cipher.getInstance("DES");
  // Initializing Cipher objects with keys
  cipher.init(Cipher.DECRYPT_MODE, securekey, random);
  // Really start decryption operation
  return cipher.doFinal(src);
 }
}

output

Before encryption:123456
 After encryption:>p.72|
After decryption:123456

3.3 asymmetric encryption

Asymmetric encryption algorithm requires two keys: public key (public key for short) and private key (private key for short).

The public key and the private key are a pair

  1. The public key encrypts the data and can only be decrypted with the corresponding private key
  2. The private key encrypts the data and can only be decrypted with the corresponding public key

Process:

  1. Party A generates a pair of keys and discloses the public key. Party B encrypts the confidential information with Party A's public key and then sends it to Party A;
  2. Party A decrypts the encrypted information with its own private key.
  3. When Party A wants to reply to Party B, Party A shall use Party B's public key to encrypt the data
  4. Party B uses its own private key to decrypt.

Party A can only decrypt any information encrypted by its public key with its private key.

characteristic:

The algorithm strength is complex

Good confidentiality

The speed of encryption and decryption is not as fast as that of symmetric encryption and decryption.

In the symmetric cryptosystem, there is only one key and it is non-public. If you want to decrypt, you have to let the other party know the key. Therefore, to ensure its security is to ensure the security of the key, while the asymmetric key system has two kinds of keys, one of which is public, so there is no need to transmit the other party's key like a symmetric password. This makes it much safer

Applicable to: finance, payment field

RSA encryption is an asymmetric encryption

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import org.apache.commons.codec.binary.Base64;
 
 
/**
 * RSA Encryption and decryption tool class
 *
 * 
 */
public class RSAUtil {
 
 public static String publicKey; // Public key
 public static String privateKey; // Private key
 
 /**
  * Generate public and private keys
  */
 public static void generateKey() {
  // 1. Initialization key
  KeyPairGenerator keyPairGenerator;
  try {
   keyPairGenerator = KeyPairGenerator.getInstance("RSA");
   SecureRandom sr = new SecureRandom(); // Random number generator
   keyPairGenerator.initialize(512, sr); // Set 512 bit long secret key
   KeyPair keyPair = keyPairGenerator.generateKeyPair(); // Start creating
   RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
   RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
   // Transcoding
   publicKey = Base64.encodeBase64String(rsaPublicKey.getEncoded());
   // Transcoding
   privateKey = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
  } catch (NoSuchAlgorithmException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
 
 /**
  * Private key encryption or decryption
  * 
  * @param content
  * @param privateKeyStr
  * @return
  */
 public static String encryptByprivateKey(String content, String privateKeyStr, int opmode) {
  // The private key should be processed with PKCS8
  PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
  KeyFactory keyFactory;
  PrivateKey privateKey;
  Cipher cipher;
  byte[] result;
  String text = null;
  try {
   keyFactory = KeyFactory.getInstance("RSA");
   // Restore Key object
   privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
   cipher = Cipher.getInstance("RSA");
   cipher.init(opmode, privateKey);
   if (opmode == Cipher.ENCRYPT_MODE) { // encryption
    result = cipher.doFinal(content.getBytes());
    text = Base64.encodeBase64String(result);
   } else if (opmode == Cipher.DECRYPT_MODE) { // decrypt
    result = cipher.doFinal(Base64.decodeBase64(content));
    text = new String(result, "UTF-8");
   }
 
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return text;
 }
 
 /**
  * Public key encryption or decryption
  * 
  * @param content
  * @param privateKeyStr
  * @return
  */
 public static String encryptByPublicKey(String content, String publicKeyStr, int opmode) {
  // The public key should be processed with X509
  X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
  KeyFactory keyFactory;
  PublicKey publicKey;
  Cipher cipher;
  byte[] result;
  String text = null;
  try {
   keyFactory = KeyFactory.getInstance("RSA");
   // Restore Key object
   publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
   cipher = Cipher.getInstance("RSA");
   cipher.init(opmode, publicKey);
   if (opmode == Cipher.ENCRYPT_MODE) { // encryption
    result = cipher.doFinal(content.getBytes());
    text = Base64.encodeBase64String(result);
   } else if (opmode == Cipher.DECRYPT_MODE) { // decrypt
    result = cipher.doFinal(Base64.decodeBase64(content));
    text = new String(result, "UTF-8");
   }
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return text;
 }
 
 // test method
 public static void main(String[] args) {
  /**
   * Note: private key encryption must be decrypted by public key encryption must be decrypted by private key
   *  // During normal development, the back-end developer generates a good key pair, the server saves the private key, and the client saves the public key
   */
  System.out.println("-------------Two pairs of secret keys are generated and kept by the sender and receiver respectively-------------");
  RSAUtil.generateKey();
  System.out.println("Public key:" + RSAUtil.publicKey);
  System.out.println("Private key:" + RSAUtil.privateKey);
 
  System.out.println("-------------Private key encryption public key decryption-------------");
   String textsr = "11111111";
   // Private key encryption
   String cipherText = RSAUtil.encryptByprivateKey(textsr,
   RSAUtil.privateKey, Cipher.ENCRYPT_MODE);
   System.out.println("After private key encryption:" + cipherText);
   // Public key decryption
   String text = RSAUtil.encryptByPublicKey(cipherText,
   RSAUtil.publicKey, Cipher.DECRYPT_MODE);
   System.out.println("After public key decryption:" + text);
 
  System.out.println("-------------Public key encryption private key decryption-------------");
  // Public key encryption
  String textsr2 = "222222";
 
  String cipherText2 = RSAUtil.encryptByPublicKey(textsr2, RSAUtil.publicKey, Cipher.ENCRYPT_MODE);
  System.out.println("After public key encryption:" + cipherText2);
  // Private key decryption
  String text2 = RSAUtil.encryptByprivateKey(cipherText2, RSAUtil.privateKey, Cipher.DECRYPT_MODE);
  System.out.print("After decryption of the private key:" + text2 );
 }
}

04 use signature to prevent data tampering

  1. Client: the requested data is divided into two parts (business parameters, signature parameters). Signature parameters = md5 (business parameters)
  2. Server: verify whether md5 (business parameter) is the same as the signature parameter

05 reference link

  • blog.csdn.net/zhou920786312/article/details/95536556