首页 > 编程知识 正文

api接口,redis击穿解决方案

时间:2023-05-05 11:42:28 阅读:156888 作者:2846

说明:目前所有的系统架构都采用前后分离的系统架构,不可避免的服务需要对外提供API。 那么,如何保证对外的API安全呢?

即,生鲜食品EC中API接口防止参数的篡改和重放攻击

目录

1 .什么是API参数篡改?

说明: API参数篡改是指恶意人通过抓取数据包获取所请求接口的参数,并修改相关参数,以达到欺骗服务器的目的,常见的防篡改方式是签名和加密方式。 关注公众号猴技术专栏获取更多面试资源

2 .什么是API重发攻击?

说明: API重放攻击:是将以前窃听的数据直接重新发送到接收方。

3、常用解决方案

常见的其他业务场景如下

发送短信界面

支付接口

基于timestamp和nonce的方案

微信支付的界面就是这样做的

timestamp角色

对于每个HTTP请求,必须添加timestamp参数,并对timestamp和其他参数进行数字签名。 由于HTTP请求从发出到到达服务器通常不超过60s,所以服务器在接收到HTTP请求后,首先判断时间戳参数与当前时间相比是否超过60s,如果超过,则判断为非法请求。

目前正在请求的timestamp参数已禁用,因为播放来自捕获的请求所需的时间通常远远超过60s。 如果将timestamp参数更改为当前时间戳,则与signature参数对应的数字签名将无效。 无法生成新的数字签名,因为您不知道签名私钥。

但是,这种方式的脆弱性也是显而易见的,60s以后进行重放攻击的话,没办法,所以用这种方式不能保证要求只有效一次

nonce的作用

nonce是指一个唯一有效的随机字符串,必须确保每个请求的此参数都不一样。 将每个请求的nonce参数存储在“集合”中,并在每次处理HTTP请求时,首先确定该请求的nonce参数是否位于该“集合”中,如果存在,则将其视为非法请求。

nonce参数在第一次请求时存储在服务器上的“集合”中,可以识别并拒绝重发请求。

nonce参数不能作为数字签名的一部分进行篡改。 无法生成新的数字签名,因为您不知道签名的私钥。

这种方式也有很大的问题。 那就是存储nonce参数的“集合”越来越大。

nonce的一次性使用可以解决timestamp参数60s (防止重放攻击)的问题,timestamp可以解决nonce参数“集合”越来越大的问题。

防篡改防重放攻击拦截器(用于redis ) ) ) ) ) ) ) ) )。

publicclassignauthinterceptorimplementshandlerinterceptor {

权限显示模板;

私有密钥;

publicsignauthinterceptor (redistemplateredistemplate,Stringkey ) )。

this.redis template=redis template;

this.key=key;

}

@Override

publicbooleanprehandle (httpservletrequestrequest,

HttpServletResponseresponse,objecthandler(Throwsexception )。

//获取时间戳

string timestamp=request.get header (timestamp );

//获取随机字符串

stringnoncestr=request.get header (' nonce str );

//得到签名

string signature=request.get header (signature );

//判断时间是否长于xx秒((防止重放攻击) ) ) ) )。

long nonce _ str _ time out _ seconds=60l;

str util.isempty (timestamp ) (|dateutil.between ) date util.date (long.parse long ) timestamp ) *1000 ),date

thrownewbusinessexception (invalidtimestamp );

}

//判断该用户的nonceStr参数是否已经进入redis (防止短时间的重放攻击) )。

booleanhavenoncestr=redis template.has key (nonce str );

str util.isempty (nonce str ) |

 Objects.isNull(haveNonceStr) || haveNonceStr) {

throw new BusinessException("invalid nonceStr");

}

// 对请求头参数进行签名

if (StrUtil.isEmpty(signature) || !Objects.equals(signature, this.signature(timestamp, nonceStr, request))) {

throw new BusinessException("invalid signature");

}

// 将本次用户请求的nonceStr参数存到redis中设置xx秒后自动删除

redisTemplate.opsForValue().set(nonceStr, nonceStr, NONCE_STR_TIMEOUT_SECONDS, TimeUnit.SECONDS);

return true;

}

private String signature(String timestamp, String nonceStr, HttpServletRequest request) throws UnsupportedEncodingException{

Map params = new HashMap<>(16);

Enumeration enumeration = request.getParameterNames();

if (enumeration.hasMoreElements()) {

String name = enumeration.nextElement();

String value = request.getParameter(name);

params.put(name, URLEncoder.encode(value, CommonConstants.UTF_8));

}

String qs = String.format("%s×tamp=%s&nonceStr=%s&key=%s", this.sortQueryParamString(params), timestamp, nonceStr, key);

log.info("qs:{}", qs);

String sign = SecureUtil.md5(qs).toLowerCase();

log.info("sign:{}", sign);

return sign;

}

/**

* 按照字母顺序进行升序排序

*

* @param params 请求参数 。注意请求参数中不能包含key

* @return 排序后结果

*/

private String sortQueryParamString(Map params){

List listKeys = Lists.newArrayList(params.keySet());

Collections.sort(listKeys);

StrBuilder content = StrBuilder.create();

for (String param : listKeys) {

content.append(param).append("=").append(params.get(param).toString()).append("&");

}

if (content.length() > 0) {

return content.subString(0, content.length() - 1);

}

return content.toString();

}

}

总结:做互联网应用,无论是生鲜小程序还是APP,安全永远都是第一位,安全做好了,其他的才能做得更好,当然,信息安全是一个永久的话题,并非通过本文就能够说得清楚的

希望本文可以给大家一点思考与建议。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。