How to prevent tampering of API parameters?

At present, all system architectures adopt a system architecture with front-end and back-end separation, so it is impossible to avoid the need for services to provide external APIs, so how to ensure the security of external APIs?

That is, the API interface in fresh food e-commerce prevents parameter tampering and replay attacks

Table of contents

1. What is API parameter tampering?

Explanation: API parameter tampering means that malicious people obtain the parameters of the requested interface by capturing packets, and modify the relevant parameters to achieve the purpose of deceiving the server. Commonly used methods to prevent tampering are signatures and encryption.

2. What is an API replay attack?

Explanation: API replay attack: It is to resend the previously eavesdropped data intact to the receiver.

3, commonly used solutions

Other commonly used business scenarios include:

Send SMS interface

payment interface

Scheme based on timestamp and nonce

The WeChat payment interface does this

The role of timestamp

For each HTTP request, the timestamp parameter needs to be added, and then the timestamp and other parameters are digitally signed. The HTTP request usually does not exceed 60s from sending to the server, so after the server receives the HTTP request, it first judges whether the timestamp parameter exceeds 60s compared with the current time, and if it exceeds, it is considered an illegal request.

Under normal circumstances, it takes far more than 60s to replay the request from the capture packet, so the timestamp parameter in the request has become invalid at this time. If the timestamp parameter is changed to the current timestamp, the digital signature corresponding to the signature parameter will become invalid. , because the signature key is not known, there is no way to generate a new digital signature.

But the loopholes of this method are also obvious. If a replay attack is performed after 60s, there is no way, so this method cannot guarantee that the request is valid only once

The role of nonce

nonce means a random string that is valid only once, and it is required that this parameter be different for each request. We store the nonce parameter of each request in a "collection". Every time an HTTP request is processed, we first judge whether the nonce parameter of the request is in the "collection". If it exists, it is considered an illegal request.

The nonce parameter has been stored in the "collection" on the server when the first request is made, and the request sent again will be recognized and rejected.

As part of the digital signature, the nonce parameter cannot be tampered with, because there is no way to generate a new digital signature without knowing the signature key.

This method also has a big problem, that is, the "set" for storing nonce parameters will become larger and larger.

The one-time use of nonce can solve the problem of timestamp parameter 60s (to prevent replay attacks), and timestamp can solve the problem of increasing nonce parameter "set".

Anti-tampering, anti-replay attack interceptor (using redis)

public class SignAuthInterceptor implements HandlerInterceptor {

private RedisTemplate<String, String> redisTemplate;

private String key;

public SignAuthInterceptor(RedisTemplate<String, String> redisTemplate, String key) {

this.redisTemplate = redisTemplate;

this.key = key;

}

@Override

public boolean preHandle(HttpServletRequest request,

HttpServletResponse response, Object handler) throws Exception {

// get timestamp

String timestamp = request.getHeader("timestamp");

// get random string

String nonceStr = request.getHeader("nonceStr");

// get the signature

String signature = request.getHeader("signature");

// Determine whether the time is greater than xx seconds (to prevent replay attacks)

long NONCE_STR_TIMEOUT_SECONDS = 60L;

if (StrUtil.isEmpty(timestamp) || DateUtil.between(DateUtil.date(Long.parseLong(timestamp) * 1000), DateUtil.date(), DateUnit.SECOND) > NONCE_STR_TIMEOUT_SECONDS) {

throw new BusinessException("invalid timestamp");

}

// Determine whether the user's nonceStr parameter is already in redis (to prevent replay attacks in a short period of time)

Boolean haveNonceStr = redisTemplate.hasKey(nonceStr);

if (StrUtil.isEmpty(nonceStr) || Objects.isNull(haveNonceStr) || haveNonceStr) {

throw new BusinessException("invalid nonceStr");

}

// Sign the request header parameters

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

throw new BusinessException("invalid signature");

}

// Save the nonceStr parameter requested by this user in redis and automatically delete it after xx seconds

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<String, Object> params = new HashMap<>(16);

Enumeration<String> 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;

}

/**

* Sort alphabetically in ascending order

*

* @param params request parameters. Note that the key cannot be included in the request parameter

* @return sorted result

*/

private String sortQueryParamString(Map<String, Object> params) {

List<String> 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();

}

}

Summary: When doing Internet applications, whether it is a fresh applet or an APP, security is always the first priority. Only when security is done well, other things can be done better. Of course, information security is a permanent topic, not through this article. able to speak clearly

I hope this article can give you some thoughts and suggestions.

Guess you like

Origin blog.csdn.net/TinagirlAPI/article/details/129488206#comments_25560588