高 困难
接口安全设计#
一句话答案#
接口安全设计五层防护:HTTPS 防窃听 → Token 认证鉴权 → 签名防篡改 → 时间戳+Nonce 防重放 → 限流防刷;对外开放 API 还需 AppKey/AppSecret + 请求签名机制。
核心要点
安全威胁与对应方案#
| 威胁 | 攻击方式 | 防御 |
|---|---|---|
| 窃听 | 抓包获取明文数据 | HTTPS (TLS) |
| 篡改 | 修改请求参数 | 签名校验 (HMAC-SHA256) |
| 重放 | 截获请求重复发送 | 时间戳 + Nonce + 签名 |
| 伪造 | 冒充合法客户端 | AppKey + Token 认证 |
| 刷接口 | 高频恶意请求 | 限流 + 验证码 + 黑名单 |
| 越权 | 访问他人数据 | 数据权限校验 |
请求签名机制#
签名生成步骤:
1. 拼接签名串: method + url + timestamp + nonce + sorted_params
2. 计算签名: sign = HMAC-SHA256(签名串, appSecret)
3. 请求附带: appKey + timestamp + nonce + sign
服务端验证:
1. 检查 timestamp 是否在 5 分钟内(防重放)
2. 检查 nonce 是否已使用(Redis SETNX,TTL 5min)
3. 用 appKey 查 appSecret
4. 用相同算法计算签名,比对是否一致(防篡改)plaintext// 客户端生成签名
String signStr = "POST" + "/api/order" + timestamp + nonce + sortedParams;
String sign = HmacUtils.hmacSha256Hex(appSecret, signStr);
// 服务端验签
@Component
public class SignVerifyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest req, ...) {
String timestamp = req.getHeader("X-Timestamp");
String nonce = req.getHeader("X-Nonce");
String sign = req.getHeader("X-Sign");
String appKey = req.getHeader("X-AppKey");
// 1. 时间戳校验(5分钟窗口)
if (Math.abs(System.currentTimeMillis() - Long.parseLong(timestamp)) > 300000) {
throw new SecurityException("Request expired");
}
// 2. Nonce 防重放
if (!redisTemplate.opsForValue().setIfAbsent("nonce:" + nonce, "1", 5, MINUTES)) {
throw new SecurityException("Duplicate request");
}
// 3. 验签
String secret = appKeyService.getSecret(appKey);
String expectedSign = computeSign(req, timestamp, nonce, secret);
if (!sign.equals(expectedSign)) {
throw new SecurityException("Invalid signature");
}
return true;
}
}java防重放三件套#
时间戳 (timestamp): 请求生成时间,服务端拒绝超过 5 分钟的请求
Nonce (一次性随机数): Redis 存已用 nonce,TTL=5min,重复拒绝
签名 (sign): 时间戳+nonce 参与签名计算,不能被篡改
三者缺一不可:
- 只有时间戳: 5分钟内可重放
- 只有nonce: 需要永久存储所有nonce(不可行)
- 时间戳+nonce: 只需存5分钟内的nonce + 签名保证不能改时间戳plaintext对外 API 安全设计#
开放平台(如支付宝/微信)标准模式:
1. 分配 AppKey (标识) + AppSecret (密钥)
2. 请求必须签名,参数按字典序排列后 HMAC
3. 敏感数据加密传输(RSA 公钥加密)
4. 回调通知也签名(双向验签)
5. IP 白名单(可选)
6. 频率限制(每秒/每天调用上限)plaintext内部接口安全#
服务间调用安全:
1. mTLS(双向 TLS):服务间证书互验
2. JWT 服务令牌:服务注册时获取,调用时携带
3. 网络隔离:内部服务不暴露公网
4. 网关统一鉴权:所有请求经 Gateway 校验后转发plaintext面试回答(2分钟版)
接口安全从外到内分五层。第一层 HTTPS 防窃听,所有通信 TLS 加密。第二层认证鉴权,JWT Token 或 AppKey 验证调用方身份。第三层签名防篡改:把请求方法、URL、参数、时间戳、Nonce 拼接后做 HMAC-SHA256 签名,服务端用同样算法验签,参数被改签名就对不上。第四层防重放:时间戳限制 5 分钟窗口 + Nonce 一次性随机数存 Redis 去重 + 两者都参与签名不能被篡改。第五层限流防刷,配合验证码和 IP 黑名单。对外开放 API 的标准模式是分配 AppKey+AppSecret,请求参数按字典序排列后签名,敏感数据 RSA 加密。内部服务间通信用 mTLS 双向认证或 JWT 服务令牌。
追问与易错
追问方向:
- “签名算法为什么用 HMAC 不用 MD5?”→ MD5 有碰撞风险且无密钥;HMAC 有密钥保证只有双方能生成有效签名
- “时间戳 5 分钟窗口会不会太长?”→ 需要容忍客户端时钟偏差,太短正常请求会被拒绝
- “Nonce 用 Redis 存会不会 OOM?”→ 设 TTL=5min(和时间戳窗口一致),自动过期不会积累
- “HTTPS 了还需要签名吗?”→ 需要,HTTPS 防第三方窃听,签名防客户端自己篡改参数
易错点:
- ❌ “有 HTTPS 就够安全了”——HTTPS 不防重放、不防客户端篡改参数
- ❌ “只校验时间戳就能防重放”——5分钟内相同请求可以无限重放
- ❌ “签名放 URL 参数里”——签名应放 Header,URL 可能被日志记录泄露