Interface encryption communication idea:
1) Agree on the secret key for communication between both parties, such as appKey = wenzhou
2) Communication security verification passed sign ature
1. Generate timestamp, random number or random string, etc., such as timestamp: time=677899002
2. The communication secret key, time stamp and parameters transmitted by the interface are spliced together through the splicing method agreed by both parties, such as:
Example 1: key1 = value1 & key2 = Value2 & Key3 = & key4 = value4 & appkey = Wenzhou & time = 677899002 &
Example 2: key1value1key2value2key3value3key4value4appKeywenzhoutime677899002
In addition, there are many, which can be agreed by users themselves
3. Agree on the complex rules of signature, such as replacing the specified characters of spliced string, character exchange before and after string, character left or right shift, etc
For example, do string exchange for example 1 of the convention method: & 200998776 = emit & uohznew = yekppa & 4eulav = 4yek & = 3yek & 2eulav = 2yek & 1eulav = 1yek
For example 2, replace the y character in the string with *: Ke * 1value1ke * 2value2ke * 3value3ke * 4value4appke * wenzhioutime677899002
There are many ways. You can make an agreement by yourself, or you can skip this step
4. Both parties agree to use the same encryption method to encrypt the final string and generate a signature (you can also capitalize all the generated signatures)
MD5, Base64, RSA # and other encryption algorithms, or write their own encryption algorithms
3) The caller passes the signature generated by the above method to the receiver together with the parameters of the interface parameters involved in generating the signature
4) The receiver generates signatures in the same way and compares whether the signatures are consistent
5) The receiver checks whether the appkeys are consistent
6) The receiver verifies the time stamp time plus the specified time length. For example, the time stamp plus 5 seconds (the effective time of the time stamp is 5 seconds). If the current time is greater than the time after the time stamp plus 5 seconds, the signature expires and access is denied
Agree on the secret key for communication between both parties (the interface provider needs to configure the appKey)
Here, I configure it in application Properties. Small partners can decide the configuration mode according to their own needs
MD5 encryption tool class (generate signature using MD5 encryption)
Here, the spliced string is encrypted to generate a signature. There are many encryption methods, such as RSA, MD5 and Base64
package com.gwssi.common.utils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.security.MessageDigest; public class MD5Util { final static Logger log = LoggerFactory.getLogger(MD5Util.class); /** * Hexadecimal number to character mapping array */ private final static String[] HEX_DIGITS = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"}; /** * md5 encryption algorithm * @param originString String to be encrypted * @return Encrypted string */ public static String encodeByMD5(String originString){ if (originString != null){ try{ //Creates an information summary with the specified algorithm name MessageDigest md = MessageDigest.getInstance("MD5"); //Use the specified byte array to make the final update to the summary, and then complete the summary calculation byte[] results = md.digest(originString.getBytes()); //Turn the resulting byte array into a string and return String resultString = byteArrayToHexString(results); return resultString.toUpperCase(); } catch(Exception ex){ log.error("md5 Encryption algorithm failed", ex); } } return null; } /** * Convert byte array to hexadecimal string * @param * @return Hexadecimal string */ private static String byteArrayToHexString(byte[] b){ StringBuffer resultSb = new StringBuffer(); for (int i = 0; i < b.length; i++){ resultSb.append(byteToHexString(b[i])); } return resultSb.toString(); } /** Converts a byte into a hexadecimal string */ private static String byteToHexString(byte b){ int n = b; if (n < 0) { n = 256 + n; } int d1 = n / 16; int d2 = n % 16; return HEX_DIGITS[d1] + HEX_DIGITS[d2]; } }
api interface provider demonstration interface signature verification
package com.gwssi.device.component; import com.gwssi.common.entity.Constant; import com.gwssi.common.entity.ResponseCode; import com.gwssi.common.entity.Result; import com.gwssi.common.utils.BgUtils; import com.gwssi.common.utils.MD5Util; import com.gwssi.common.utils.ThreadCache; import net.sf.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.Map; @Component public class WenZhouComponent { Logger log = LoggerFactory.getLogger(WenZhouComponent.class); @Value("${wenzhou.appKey}") String localAppKey; @SuppressWarnings("unchecked") public Map<String,Object> wenzhouApis(){ //Get request parameters JSONObject js = JSONObject.fromObject(ThreadCache.getData(Constant.HTTP_PARAM)); Map<String,Object> map = (Map<String,Object>) js; //map data is all parameters passed by the caller_ sign the signature generated by the caller through the agreed rules, the timestamp generated by the time caller, the secret key agreed by both parties, and the type is a common mandatory parameter //Required parameter verification if(!BgUtils.cheakParamIsNull(map, Arrays.asList("_sign","time","type","appKey"))){ Result.putValue(ResponseCode.CodeEnum.REQUIRED_PARAM_NULL); return null; } //Signature verification if(!checkSign(map.get("_sign").toString(),map.get("appKey").toString(),Long.parseLong(map.get("time").toString()),map)){ return null; } int type = Integer.parseInt(map.get("type").toString()); //Perform interface body operation return null; } //api connection security check private boolean checkSign(String getSign,String appKey,long time,Map<String,Object> map){ //The receiver checks whether the appkeys are consistent //Whether the appKey configuration is consistent log.info("Configure local appkey:"+localAppKey+" transmit appkey:"+appKey); if(!appKey.equals(localAppKey)){ Result.putValue(ResponseCode.CodeEnum.APP_KEY_ERROR); return false; } //The receiver generates signatures in the same way and compares whether the signatures are consistent //The signature rule here is to concatenate all the incoming parameters (except the sign signature parameters) in order, key = value & together, then perform MD5 encryption, and then capitalize all the encrypted results, which is the signature generation rule StringBuffer str = new StringBuffer(""); map.keySet().stream().filter(c->!c.equals("_sign")).forEach(c->str.append(c).append("=").append(map.get(c).toString()).append("&")); String mySign = MD5Util.encodeByMD5(str.toString()); //Whether the signature calculation rules are consistent log.info("Encrypted string:"+str.toString()+" Calculate signature:"+mySign+" Delivery signature:"+getSign); if(!getSign.equals(mySign.toUpperCase())){ Result.putValue(ResponseCode.CodeEnum.PARAM_SIGN_INCORRECT); return false; } //The receiver verifies the time stamp time plus the specified time length. For example, the time stamp plus 5 seconds (the effective time of the time stamp is 5 seconds). If the current time is greater than the time after the time stamp plus 5 seconds, the signature expires and access is denied //Signature expiration judgment (the time stamp is valid for only 5 seconds) if(new Date(time+5000).compareTo(new Date()) < 0){ log.info("Signed on"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(time+5000))+"Post expiration"); Result.putValue(ResponseCode.CodeEnum.SIGN_EXPIRE); return false; } return true; } }
api interface address demonstration
@ApiOperation("Provided by Wenzhou api Interface address encapsulation") @RequestMapping("/device/wenzhouApis") public void wenzhouApis(){ wenZhouComponent.wenzhouApis(); }
Request demo
Simulated caller request:
Receiver:
2021-05-18 17:34:24.682 [ http-nio-9080-exec-2 ] - [ INFO ] [ o.a.c.core.ContainerBase.[Tomcat].[localhost].[/] : 180 ] - Initializing Spring FrameworkServlet 'dispatcherServlet' 2021-05-18 17:34:24.683 [ http-nio-9080-exec-2 ] - [ INFO ] [ org.springframework.web.servlet.DispatcherServlet : 494 ] - FrameworkServlet 'dispatcherServlet': initialization started 2021-05-18 17:34:24.761 [ http-nio-9080-exec-2 ] - [ INFO ] [ org.springframework.web.servlet.DispatcherServlet : 509 ] - FrameworkServlet 'dispatcherServlet': initialization completed in 78 ms 2021-05-18 17:34:24.891 [ http-nio-9080-exec-2 ] - [ INFO ] [ com.gwssi.filter.ParameterFilter : 79 ] - http-nio-9080-exec-2 --- Request Begin --- /device/wenzhouApis,body={ "_sign":"EC7ED24DF32F306E8F4E822E263289A3", "time":"677899002", "type":"1", "appKey":"wenzhou" } 2021-05-18 17:34:24.891 [ http-nio-9080-exec-2 ] - [ INFO ] [ com.gwssi.filter.ParameterFilter : 83 ] - http-nio-9080-exec-2 --- Request Begin --- /device/wenzhouApis,sysuid= 2021-05-18 17:34:25.053 [ http-nio-9080-exec-2 ] - [ INFO ] [ com.gwssi.device.component.WenZhouComponent : 58 ] - Configure local appkey:wenzhou transmit appkey:wenzhou 2021-05-18 17:34:25.057 [ http-nio-9080-exec-2 ] - [ INFO ] [ com.gwssi.device.component.WenZhouComponent : 67 ] - Encrypted string:time=677899002&type=1&appKey=wenzhou& Calculate signature:EC7ED24DF32F306E8F4E822E263289A3 Delivery signature:EC7ED24DF32F306E8F4E822E263289A3 2021-05-18 17:34:25.058 [ http-nio-9080-exec-2 ] - [ INFO ] [ com.gwssi.device.component.WenZhouComponent : 75 ] - Signed in 1970-01-09 04:18:24 Post expiration 2021-05-18 17:34:25.149 [ http-nio-9080-exec-2 ] - [ INFO ] [ com.gwssi.interceptor.ParameterInterceptor : 33 ] - http-nio-9080-exec-2 --- /device/wenzhouApis --- Request End --- {"code":14,"data":null,"msg":"Signature expired"} 2021-05-18 17:34:25.150 [ http-nio-9080-exec-2 ] - [ INFO ] [ com.gwssi.interceptor.ParameterInterceptor : 34 ] - http-nio-9080-exec-2 --- /device/wenzhouApis --- Request Time --- 2021-05-18 17:34:24.905 used 245ms
Online MD5 encryption display: it can be seen that the encryption result is consistent with that of MD5Util
Summary
1) the provider and the caller of the interface agree on a unified parameter encryption algorithm to obtain a sign ature
2) When retrieving parameters, the caller will pass the parameters for calculating the signature sign, the required parameters and the signature to the interface
3) The interface provider encrypts the parameters obtained according to the agreed parameter encryption algorithm to obtain a signature. Compare whether the two signatures are consistent. If they are inconsistent, the interface stops the remaining operations
4) After the signature verification is passed, if the user still has the setting of the effective duration of the signature, he can also ask the provider to pass the timestamp (the time of the receiver is required to be consistent with that of the provider or the redundant time difference during calculation). The timestamp + effective duration is compared with the current time. If it is less than the current duration and the timestamp expires, the interface will stop the remaining operations
5) In order to further ensure security, both parties can also agree to use the public key for encryption. This public key can generally be saved by itself and not passed as a parameter (in this case, it is passed as a parameter, which is generally not recommended)
6) Recommend using https protocol instead of http