Information Security 14 min read

Secure API Design for Microservices: Anti‑Tampering, Anti‑Replay, and Authentication Strategies

This article explains how to protect microservice APIs from tampering and replay attacks by using HTTPS, request signing, nonce‑timestamp mechanisms, and AppId/AppSecret authentication, and demonstrates a complete Java/Spring implementation with a responsibility‑chain based verification filter.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Secure API Design for Microservices: Anti‑Tampering, Anti‑Replay, and Authentication Strategies

When exposing microservice APIs to third parties, ensuring their security requires protecting against tampering and replay attacks.

1. What is a Secure Interface

A secure API must provide anti‑tampering and anti‑replay capabilities.

1.1 Tampering Problem

Because HTTP is stateless, an attacker can capture a request such as http://localhost/api/user/recharge?user_id=1001&amount=10 and modify parameters to add arbitrary balance.

1.1.1 Solution

Two common solutions are:

Use HTTPS to encrypt the transmission.

Sign request parameters on the server side and verify the signature.

The signing process involves the client generating a signature (sign1) and sending it with the request; the server recomputes the signature (sign2) and compares the two values.

1.2 Replay Problem

Replay attacks reuse a captured request without modification, causing duplicate data or overwhelming slow‑query endpoints.

1.2.1 Solution

Implement a nonce + timestamp scheme: each request includes a unique random string and the current timestamp, both of which are signed. The server checks that the timestamp is within an acceptable window (e.g., 60 seconds) and that the nonce has not been used before (typically stored in Redis).

2. Authentication Scheme

Access to public APIs is restricted using AppId and AppSecret . The client sends AppId , timestamp , nonce , and other parameters; the server retrieves the corresponding AppSecret , appends it to the sorted parameter string, hashes the result (MD5), and compares it with the client‑provided signature.

2.1 Signing Process

Server provides a pair of AppId and AppSecret to the client.

Client builds a string StringA by sorting all parameters (including timestamp , nonce , AppId ) as key1=value1&key2=value2… .

Append AppSecret to obtain StringB .

Hash StringB (MD5) and convert to uppercase to get the signature sign , then send it with the request.

Server recomputes the signature and validates it together with timestamp and nonce.

3. Code Implementation

The following Java/Spring code demonstrates the complete solution.

3.1 Generating AppId and AppSecret

private static String getAppKey() {
    long num = IdUtils.nextId();
    StringBuilder sb = new StringBuilder();
    do {
        int remainder = (int) (num % 62);
        sb.insert(0, BASE62_CHARACTERS.charAt(remainder));
        num /= 62;
    } while (num != 0);
    return sb.toString();
}

Example output: appKey=6iYWoL2hBk9, appSecret=5de8bc4d8278ed4f14a3490c0bdd5cbe369e8ec9

3.2 API Authenticator Interface

public interface ApiAuthenticator {
    AuthenticatorResult auth(ServerWebExchange request);
}

3.3 Gateway Filter

@Component
@Slf4j
public class ApiAuthenticatorFilter implements GlobalFilter, Ordered {
    @Override
    public Mono
filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ApiAuthenticator apiAuthenticator = getApiAuthenticator(rawPath);
        AuthenticatorResult result = apiAuthenticator.auth(exchange);
        if (!result.isResult()) {
            return Mono.error(new HttpServerErrorException(HttpStatus.METHOD_NOT_ALLOWED, result.getMessage()));
        }
        return chain.filter(exchange);
    }
    // ... method to resolve authenticator based on path
}

3.4 Responsibility‑Chain Verification

Each verification step (parameter check, nonce check, timestamp check, signature check) is implemented as a SecurityVerificationHandler with an order value. The SecurityVerificationChain iterates over the handlers and stops on the first failure.

public interface SecurityVerificationHandler extends Ordered {
    AuthenticatorResult handler(ProtectedRequest protectedRequest);
}

Example handler for nonce verification:

@Component
public class NonceVerificationHandler implements SecurityVerificationHandler {
    @Value("${dailymart.sign.timeout:60000}")
    private long expireTime;
    @Resource
    private DistributedCache distributedCache;
    @Override
    public AuthenticatorResult handler(ProtectedRequest request) {
        String nonce = request.getRequestHeader().getNonce();
        if (distributedCache.hasKey("x-nonce-" + nonce)) {
            return new AuthenticatorResult(false, "请勿重复提交请求");
        }
        distributedCache.put("x-nonce-" + nonce, nonce, expireTime);
        return new AuthenticatorResult(true, "");
    }
    @Override
    public int getOrder() { return 3; }
}

The chain aggregates results and returns success only if all handlers pass.

Conclusion

The article demonstrates how to secure external microservice APIs by combining HTTPS, request signing, nonce‑timestamp anti‑replay mechanisms, and an AppId/AppSecret authentication model, and provides a modular, extensible Java/Spring implementation using the responsibility‑chain pattern.

microservicestimestampresponsibility chainAPI securitySignaturenonce
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.