sign数据推送验证机制
说明
在每刻调用您的接口时,为了保证数据在推送过程中没有发生篡改行为,会在head中添加sign字段以表示此次responseBody的签名来保证数据没有发生篡改行为,用户在接收每刻推送的数据前应该对requestBody按照以下验证方式获取签名值和head中的签名值做比对,如一致则认为数据没有被篡改过。
验证流程
- 首先根据每刻分配的secret(此秘钥为单独分配,非鉴权接口所使用的的appSecret)对requestBody的数据进行签名,签名方式如下,value为requestBody中的数据,key为每刻分配的secret。注: 用户在接收到requestBody时不应该做任何对象转换,可以考虑直接用String去接收,先将requestBody做签名验证,然后再将requestBody转换成用户自己需要的对象
- 获取签名数据后,根据下面的Sign方法获取签名的sign值并和每刻推送的数据中的head中的sign值做比较,如一致则认为请求合法
示例
获取数据签名
import com.maycur.common.exception.NAckException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public String encryptCbcMode(final String value, String key) {
if (StringUtils.isNotBlank(value)) {
final SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "AES");
//初始化向量器
final IvParameterSpec ivParameterSpec = new IvParameterSpec(Arrays.copyOfRange(key.getBytes(), 0, 16));
try {
//加密模式
Cipher encipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
encipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec);
//加密
byte[] encrypted = encipher.doFinal(value.getBytes(StandardCharsets.UTF_8));
//然后转成BASE64返回
return Base64.encodeBase64String(encrypted);
} catch (Exception e) {
logger.error("使用AES加密失败, errorMsg:{}, cause:{}", e.getMessage(), e.getCause());
}
}
return value;
}
Sign
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
/**
* json是签名后的数据
*/
public static int getHashValue(String encryptValue) {
return Hashing.md5().newHasher().putString(encryptValue, Charsets.UTF_8).hash().asInt();
}