|
|
package com.yohoufo.common.interceptor;
|
|
|
|
|
|
import com.google.common.collect.ImmutableList;
|
|
|
import com.netflix.config.DynamicPropertyFactory;
|
|
|
import com.yoho.core.common.utils.MD5;
|
|
|
import com.yoho.core.config.ConfigReader;
|
|
|
import com.yoho.error.event.LogEvent;
|
|
|
import com.yohoufo.common.annotation.IgnoreSignature;
|
|
|
import com.yohoufo.common.exception.SignatureNotMatchException;
|
|
|
import com.yohoufo.common.utils.MD5Util;
|
|
|
import com.yohoufo.common.utils.ServletUtils;
|
|
|
import java.lang.reflect.Method;
|
|
|
import java.net.InetAddress;
|
|
|
import java.net.UnknownHostException;
|
|
|
import java.util.Arrays;
|
|
|
import java.util.LinkedList;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
|
import org.apache.commons.lang.StringUtils;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
...
|
...
|
@@ -18,23 +21,17 @@ import org.springframework.web.method.HandlerMethod; |
|
|
import org.springframework.web.servlet.HandlerInterceptor;
|
|
|
import org.springframework.web.servlet.ModelAndView;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
import javax.crypto.Mac;
|
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
import java.lang.reflect.Method;
|
|
|
import java.net.InetAddress;
|
|
|
import java.net.UnknownHostException;
|
|
|
import java.util.*;
|
|
|
import com.yoho.core.config.ConfigReader;
|
|
|
import com.yoho.error.event.LogEvent;
|
|
|
import com.yoho.signature.MsgSign;
|
|
|
import com.yohoufo.common.annotation.IgnoreSignature;
|
|
|
import com.yohoufo.common.exception.SignatureNotMatchException;
|
|
|
import com.yohoufo.common.utils.ServletUtils;
|
|
|
|
|
|
public class SignatureVerifyInterceptor implements HandlerInterceptor, ApplicationEventPublisherAware {
|
|
|
|
|
|
private final Logger logger = LoggerFactory.getLogger(SignatureVerifyInterceptor.class);
|
|
|
|
|
|
//验签算法
|
|
|
private final static String VERIFY_ARITHMETIC = "HmacSHA256";
|
|
|
|
|
|
//客户端加签请求头
|
|
|
private final static String HTTP_HEADER_VERIFY_DATA = "x-yoho-verify";
|
|
|
|
...
|
...
|
@@ -74,20 +71,18 @@ public class SignatureVerifyInterceptor implements HandlerInterceptor, Applicati |
|
|
if(this.validateReqParams(httpServletRequest, params)){
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
//(4) 预留后门, 如果是内网并且传入_sncp参数, 并且验证成功, 不验证.
|
|
|
String temporaryValueQeq = params.get("_sncp"); //请求的预留后门的值
|
|
|
String temporaryValue = configReader.getString("gateway.client.secret.h5", "");
|
|
|
logger.debug("SignatureVerifyInterceptor. method is {}, temporaryValueQeq is {}, temporaryValue is {} and isInner is {}", method, temporaryValueQeq, temporaryValue);
|
|
|
if (!StringUtils.isEmpty(temporaryValueQeq) && !StringUtils.isEmpty(temporaryValue) && temporaryValueQeq.trim().equals(temporaryValue.trim()) && isInnerIp(httpServletRequest)){
|
|
|
|
|
|
//(4) 验证参数
|
|
|
MsgSign msgSign = new MsgSign();
|
|
|
if (msgSign.paramVerify(params) && isInnerIp(httpServletRequest,false)){
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
//(4) 验证消息签名.
|
|
|
String message = this.getPramsString(params);
|
|
|
String message = msgSign.getPramsString(params);
|
|
|
String verifyMessage = httpServletRequest.getHeader(HTTP_HEADER_VERIFY_DATA);
|
|
|
logger.debug("verifySignature: message is {}, verifyMessage is {}", message, verifyMessage);
|
|
|
boolean verifyRes = this.verifySignatureNew(udid, message, verifyMessage);
|
|
|
boolean verifyRes = msgSign.verifySign(udid, message, verifyMessage, false, appVersion);
|
|
|
logger.debug("verifySignature: message is {}, verifyMessage is {}, res is {}", message, verifyMessage, verifyRes);
|
|
|
|
|
|
if(!verifyRes){
|
...
|
...
|
@@ -172,7 +167,7 @@ public class SignatureVerifyInterceptor implements HandlerInterceptor, Applicati |
|
|
private boolean validateReqParams(HttpServletRequest request, Map<String, String> params){
|
|
|
//内网访问的pc/h5不作校验
|
|
|
String clientType = params.get("client_type");
|
|
|
if(("web".equals(clientType) || "h5".equals(clientType) || "wechat".equals(clientType)) && isInnerIp(request)){
|
|
|
if(("web".equals(clientType) || "h5".equals(clientType) || "wechat".equals(clientType)) && isInnerIp(request, true)){
|
|
|
return true;
|
|
|
}
|
|
|
//是否校验全部接口,开关-true:校验全部接口(除含@IgnoreSignature注解接口) 开关-false:只校验核心接口
|
...
|
...
|
@@ -193,12 +188,13 @@ public class SignatureVerifyInterceptor implements HandlerInterceptor, Applicati |
|
|
/**
|
|
|
* 是否内网ip
|
|
|
* @param request
|
|
|
* @param 是否强制验证
|
|
|
* @return
|
|
|
*/
|
|
|
public boolean isInnerIp(HttpServletRequest request){
|
|
|
public boolean isInnerIp(HttpServletRequest request, boolean enFlag){
|
|
|
//增加内网ip验证开关,供压测时使用
|
|
|
boolean isInnerIpVerifyEnable = configReader.getBoolean("gateway.security.isInnerIpVerifyEnable", true);
|
|
|
if(!isInnerIpVerifyEnable){
|
|
|
if(!isInnerIpVerifyEnable && !enFlag){
|
|
|
return true;
|
|
|
}
|
|
|
String ip = getRemoteIP( request );
|
...
|
...
|
@@ -243,31 +239,6 @@ public class SignatureVerifyInterceptor implements HandlerInterceptor, Applicati |
|
|
return ServletUtils.getRequestParams(httpServletRequest);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 拼接请求参数,k1=v1&k2=v2
|
|
|
* @param reqParams
|
|
|
* @return
|
|
|
*/
|
|
|
private String getPramsString(Map<String, String> reqParams) {
|
|
|
ImmutableList list = ImmutableList.of();
|
|
|
SortedMap<String, String> filtedMap = new TreeMap<>();
|
|
|
for (Map.Entry<String, String> entry : reqParams.entrySet()) {
|
|
|
String k = entry.getKey();
|
|
|
if (!list.contains(k)) {
|
|
|
filtedMap.put(k, entry.getValue());
|
|
|
}
|
|
|
}
|
|
|
//string: k1=v1&k2=v2
|
|
|
List<String> array = new LinkedList<>();
|
|
|
for (Map.Entry<String, String> entry : filtedMap.entrySet()) {
|
|
|
String pair = entry.getKey() + "=" + entry.getValue();
|
|
|
array.add(pair.trim());
|
|
|
}
|
|
|
String paramStr = String.join("&", array);
|
|
|
logger.debug("getRequestInfo: param str is: {}", paramStr);
|
|
|
return paramStr;
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 验证签名
|
...
|
...
|
@@ -276,25 +247,25 @@ public class SignatureVerifyInterceptor implements HandlerInterceptor, Applicati |
|
|
* @param verifyMessage
|
|
|
* @return
|
|
|
*/
|
|
|
private boolean verifySignatureNew(String udid, String message, String verifyMessage){
|
|
|
//(1) 验证信息为空或者udid为空,直接返回
|
|
|
if(StringUtils.isEmpty(verifyMessage) || StringUtils.isEmpty(udid)){
|
|
|
return false;
|
|
|
}
|
|
|
//(2) 获取秘钥
|
|
|
String md5Salt = DynamicPropertyFactory.getInstance().getStringProperty("gateway.signature.key.salt", "mQyMTMwZjlmZTZmYjY4UjkNmYwZGM0OTk0Y").get();
|
|
|
String encryptStr = udid + md5Salt;
|
|
|
//对udid加盐后二次md5
|
|
|
String signatureKey = MD5.md5(MD5.md5(encryptStr));
|
|
|
|
|
|
//(3) 对消息加签
|
|
|
String signatureRes = this.HmacSHA256(message, signatureKey);
|
|
|
if(verifyMessage.equals(signatureRes)){
|
|
|
return true;
|
|
|
}
|
|
|
logger.warn("verifySignatureNew: signature verify failed: message is {}, verifyMessage is {}, udid is {}, key is {}", message, verifyMessage, udid, signatureKey);
|
|
|
return false;
|
|
|
}
|
|
|
// private boolean verifySignatureNew(String udid, String message, String verifyMessage){
|
|
|
// //(1) 验证信息为空或者udid为空,直接返回
|
|
|
// if(StringUtils.isEmpty(verifyMessage) || StringUtils.isEmpty(udid)){
|
|
|
// return false;
|
|
|
// }
|
|
|
// //(2) 获取秘钥
|
|
|
// String md5Salt = DynamicPropertyFactory.getInstance().getStringProperty("gateway.signature.key.salt", "mQyMTMwZjlmZTZmYjY4UjkNmYwZGM0OTk0Y").get();
|
|
|
// String encryptStr = udid + md5Salt;
|
|
|
// //对udid加盐后二次md5
|
|
|
// String signatureKey = MD5.md5(MD5.md5(encryptStr));
|
|
|
//
|
|
|
// //(3) 对消息加签
|
|
|
// String signatureRes = this.HmacSHA256(message, signatureKey);
|
|
|
// if(verifyMessage.equals(signatureRes)){
|
|
|
// return true;
|
|
|
// }
|
|
|
// logger.warn("verifySignatureNew: signature verify failed: message is {}, verifyMessage is {}, udid is {}, key is {}", message, verifyMessage, udid, signatureKey);
|
|
|
// return false;
|
|
|
// }
|
|
|
|
|
|
/**
|
|
|
* 签名失败上报事件
|
...
|
...
|
@@ -312,26 +283,26 @@ public class SignatureVerifyInterceptor implements HandlerInterceptor, Applicati |
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 使用hmac加密
|
|
|
* @param data
|
|
|
* @param secret
|
|
|
* @return
|
|
|
*/
|
|
|
private String HmacSHA256(String data, String secret){
|
|
|
String res = null;
|
|
|
try{
|
|
|
Mac sha256_HMAC = Mac.getInstance(VERIFY_ARITHMETIC);
|
|
|
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), VERIFY_ARITHMETIC);
|
|
|
sha256_HMAC.init(secret_key);
|
|
|
byte[] encryptByte = sha256_HMAC.doFinal(data.getBytes());
|
|
|
res = MD5Util.byteArrayToHexString(encryptByte);
|
|
|
logger.debug("HmacSHA256: data is {}, secret is {}, res is {}", data, secret, res);
|
|
|
}catch (Exception e){
|
|
|
logger.warn("HmacSHA256: hmac failed, data is {}, error is {}", data, e);
|
|
|
}
|
|
|
return res;
|
|
|
}
|
|
|
// /**
|
|
|
// * 使用hmac加密
|
|
|
// * @param data
|
|
|
// * @param secret
|
|
|
// * @return
|
|
|
// */
|
|
|
// private String HmacSHA256(String data, String secret){
|
|
|
// String res = null;
|
|
|
// try{
|
|
|
// Mac sha256_HMAC = Mac.getInstance(VERIFY_ARITHMETIC);
|
|
|
// SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), VERIFY_ARITHMETIC);
|
|
|
// sha256_HMAC.init(secret_key);
|
|
|
// byte[] encryptByte = sha256_HMAC.doFinal(data.getBytes());
|
|
|
// res = MD5Util.byteArrayToHexString(encryptByte);
|
|
|
// logger.debug("HmacSHA256: data is {}, secret is {}, res is {}", data, secret, res);
|
|
|
// }catch (Exception e){
|
|
|
// logger.warn("HmacSHA256: hmac failed, data is {}, error is {}", data, e);
|
|
|
// }
|
|
|
// return res;
|
|
|
// }
|
|
|
|
|
|
//含忽略签名校验注解的接口,不验证
|
|
|
private boolean isVerifySignature(HandlerMethod handlerMethod, String clientType, String appVersion){
|
...
|
...
|
|