OpenAPI Security Practices: AppId/AppSecret, Signature Generation, and Implementation Guide
This article explains how to use OpenAPI standards to secure API interfaces by introducing AppId/AppSecret mechanisms, RSA‑based signatures, timestamp and nonce anti‑replay measures, and provides complete Java code examples for client‑side signing and server‑side verification along with common protection techniques such as rate limiting and data validation.
To ensure standardized, reusable, and secure API interfaces, the OpenAPI specification defines a unified protocol for request parameters, signatures, and authentication, improving maintainability and extensibility.
1. AppId and AppSecret
AppId usage
AppId is a globally unique identifier used for user identification and data analysis. It is paired with AppSecret (a password‑like secret) to prevent malicious requests.
AppId generation
When generating an AppId , ensure global uniqueness; no additional algorithmic constraints are required.
AppSecret generation
AppSecret follows typical password‑strength rules and is treated as a secret key.
2. sign signature
RSASignature combines asymmetric encryption (RSA) with a hash algorithm (e.g., MD5 or SHA‑256) to produce a digital signature. The workflow includes:
Data hashing (digest) using MD5 or SHA‑256.
RSA private‑key signing of the hash.
RSA public‑key verification on the receiver side.
The signature protects against data tampering and identity spoofing.
Data anti‑tampering
Hashing guarantees that the same original data always yields the same digest; any modification changes the digest, allowing detection.
Identity anti‑spoofing
Using SHA256withRSA , the client hashes the request data, signs it with its private key, and the server verifies the signature with the corresponding public key.
3. Usage Example
Pre‑conditions
When no automated platform exists, the appId and appSecret are exchanged offline.
The provider generates a public‑private key pair for each appId and shares the public key with the client.
Client workflow
UserEntity userEntity = new UserEntity();
userEntity.setUserId("1");
userEntity.setPhone("13912345678");
String sign = getSHA256Str(JSONObject.toJSONString(userEntity));
Map
data = Maps.newHashMap();
data.put("appId", appId);
data.put("nonce", nonce);
data.put("sign", sign);
data.put("timestamp", timestamp);
// sort, concatenate, append appSecret, then sign with RSA private key
String appSign = sha256withRSASignature(privateKey, concatenatedParams);
Header header = Header.builder()
.appId(appId).nonce(nonce).sign(sign).timestamp(timestamp).appSign(appSign).build();
APIRequestEntity request = new APIRequestEntity();
request.setHeader(header);
request.setBody(userEntity);
String requestParam = JSONObject.toJSONString(request);Server workflow
Header header = apiRequestEntity.getHeader();
UserEntity user = JSONObject.parseObject(JSONObject.toJSONString(apiRequestEntity.getBody()), UserEntity.class);
String sign = getSHA256Str(JSONObject.toJSONString(user));
if (!sign.equals(header.getSign())) throw new Exception("Data signature error!");
String appSecret = getAppSecret(header.getAppId());
Map
data = new HashMap<>();
data.put("appId", header.getAppId());
data.put("nonce", header.getNonce());
data.put("sign", sign);
data.put("timestamp", header.getTimestamp());
String sb = buildSortedString(data) + "appSecret=" + appSecret;
if (!rsaVerifySignature(sb, publicKey, header.getAppSign())) throw new Exception("Public key verification error!");
System.out.println("Verification passed!");4. Common Protection Measures
Timestamp
The timestamp parameter limits request validity (e.g., 5‑minute window) to prevent replay attacks.
long now = System.currentTimeMillis();
if ((now - Long.parseLong(timestamp)) / 1000 / 60 >= 5) throw new Exception("Request expired!");Nonce
A random nonce ensures each request is used only once; the server stores used nonces (e.g., Guava cache or Redis) and rejects duplicates.
static Cache
cache = CacheBuilder.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
String key = appId + "_" + nonce;
if (cache.getIfPresent(key) != null) throw new Exception("Request invalid!");
cache.put(key, "1");Access Permission
APIs should enforce permission checks based on appId to restrict data access to authorized scopes.
Parameter Validation
All request parameters must be validated (length, type, format, required fields). SpringBoot Validation annotations (e.g., @NotBlank, @Email, @Size) are recommended.
@NotBlank(message = "Name cannot be empty")
private String name;
@Email
private String email;
@DecimalMin("5") @DecimalMax("10")
private BigDecimal amount;Rate Limiting
Use Guava RateLimiter for single‑node limits or Redis/Sentinel for distributed throttling.
Sensitive Data Masking
Mask personal identifiers (ID, phone, bank card) before storage or transmission.
5. Additional Considerations
Clear API naming and description.
Support standard HTTP methods (GET, POST, PUT, DELETE) with defined request/response formats.
Define error codes and detailed messages.
Provide documentation and sample data.
Design for extensibility (versioning, backward compatibility).
6. Supplementary Topics
MD5 Usage
MD5 produces a fixed‑length, irreversible hash useful for password storage, but vulnerable to rainbow‑table attacks; adding a salt mitigates this risk.
String pwd = "123456";
String salt = "wylsalt";
String hashed = DigestUtils.md5Hex(salt + pwd);
System.out.println("MD5 with salt: " + hashed);Symmetric Encryption
Examples of DES, 3DES, and AES encryption modes (ECB vs. CBC) are provided, highlighting security trade‑offs.
private static final String AES_ECB_PCK_ALG = "AES/ECB/NoPadding";
public static String encryptWithECB(String content, String aesKey, String charset) throws Exception {
Cipher cipher = Cipher.getInstance(AES_ECB_PCK_ALG);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(aesKey.getBytes()), "AES"));
return Hex.encodeHexString(cipher.doFinal(content.getBytes(charset)));
}Overall, the guide combines theoretical security concepts with practical Java implementations to help developers build robust, tamper‑proof, and authenticated OpenAPI services.
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
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.