接口参数防篡改处理

向外网开发的接口,由于外网环境的复杂,容易被人获取到请求地址,以及真是的请求参数,就能够使用该参数再次请求,造成重放攻击;或者黑客直接篡改请求参数。

为了防止请求参数被篡改,需要对参数进行加密。

这里采用的是每次请求根据月的的密钥生成签名sign,在请求到达后台服务器时对请求参数再次进行校验生成签名,比较两次签名。如果一致则认为请求参数没有被篡改,如果不一致则认为请求参数已经被篡改,拦截请求。

下面代码实现

public class RequestCryptoHelper {
	//密钥
	private static String signKeys = "xxxxxxx";
	
	public static String sha1(String value) {
		if (value == null) {
			return null;
		}
		try {
			MessageDigest digest = java.security.MessageDigest.getInstance("SHA-1");
			digest.update(value.getBytes());
			byte messageDigest[] = digest.digest();
			// Create Hex String
			StringBuffer hexString = new StringBuffer();
			// 字节数组转换为 十六进制数
			for (int i = 0; i < messageDigest.length; i++) {
				String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
				if (shaHex.length() < 2) {
					hexString.append(0);
				}
				hexString.append(shaHex);
			}
			return hexString.toString();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	* 这里对请求参数字符串进行处理,去掉所有的空格,和双引号
	* 以防止不同系统对于参数处理不同
	*/
	public static String crypto(String signString){
		signString = signString + signKeys;
		signString = signString.replaceAll("\"", "")
								.replaceAll(" ", "");
		return RequestCryptoHelper.sha1(signString.toLowerCase());
	}
}

这里是spring boot项目,所以拦截器继承了HandlerInterceptorAdapter实现请求的拦截处理,
这里同时将时间戳一起传递,拦截超时请求,这里设置的超时时间是30秒。

@Component
public class RequestParamVerifyInterceptor extends HandlerInterceptorAdapter {
	//这里是对springmvc中路径传参的加密,约定路径传参,在请求头加上(pathvariable: 路径)
	//在参数加密时也一起加密
	private static final String PATH_VARIABLE = "pathvariable";
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		try {
			Map<String, Object> params = new HashMap<>();
			Map<String, String[]> parameterMap = request.getParameterMap();
			Iterator<String> iterator = parameterMap.keySet().iterator();
		    while (iterator.hasNext()) {
		        String key = iterator.next();
		        String[] valueArr = parameterMap.get(key);
		        //这里约定参数不重复
		        params.put(key, valueArr[0]);
		    }
		    String pathvariable = request.getHeader(PATH_VARIABLE);
		    StringBuffer requestURL = request.getRequestURL();
		    if(pathvariable != null) {
		    	if(!requestURL.toString().endsWith(pathvariable)) {
		    		throw new Exception("error:路径传参错误!");
		    	}
		    	if(params.containsKey(PATH_VARIABLE))
		    	params.put(PATH_VARIABLE, pathvariable);
		    }
		    
			if (request.getHeader("sign") == null || request.getHeader("timestamp") == null) {
				throw new Exception("error:参数错误,缺少必要参数!");
			}
			long timestamp = Long.parseLong(request.getHeader("timestamp"));
			long now = System.currentTimeMillis();
			long diffMillis = now - timestamp;
			/// 30秒
			if ( diffMillis >= 30*1000 ) {
				throw new Exception("error:请求失效!");
			}
			Set<String> keysSet = params.keySet();  
			Object[] keys = keysSet.toArray(); 
			Arrays.sort(keys);  
			StringBuffer temp = new StringBuffer();  
			for (Object key : keys) {
				if(key.equals("sign") || key.equals("timestamp")){
					continue;
				}
				temp.append("&"); 
				temp.append(key).append("=");  
				Object value = params.get(key);  
				String valueString = "";  
				if (null != value) {  
					valueString = String.valueOf(value).toLowerCase();  
				}   
				temp.append(valueString);  
			} 
			String sign = request.getHeader("sign");
			String signString = temp.toString().substring(1)+"×tamp="+timestamp;
			String signedString = RequestCryptoHelper.crypto(signString);
			boolean result = sign.equals(signedString) ? true : false;
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		
	}

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		
	}

}

注意:
这里需要注意的是,由于参数从前台传到后台,顺序可能发生改变。所以需要对参数进行排序,代码示例中按照参数名排序。

将拦截器注册到springboot项目中。

@Configuration
public class WebAppConfigurer extends WebMvcConfigurerAdapter{
	@Autowired
	private RequestParamVerifyInterceptor requestParamVerifyInterceptor;
	
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		registry.addInterceptor(requestParamVerifyInterceptor).addPathPatterns("/**");
	}
}

你可能感兴趣的:(java)