實戰出真知!SpringBoot 接口級防護:限流、重放攻擊與簽名機制全解析
在當今數字化服務廣泛開放的背景下,后端接口往往暴露在公網之下,極易成為攻擊者的突破口。接口調用的重放攻擊、參數偽造、暴力請求等問題屢見不鮮,嚴重威脅服務安全與數據完整性。
本文將基于 Spring Boot 框架,手把手實現一套可落地的接口安全防護機制,涵蓋簽名驗證、防重放、限流控制等核心能力,適用于 B 端開放接口、系統對接場景。
接口簽名驗證設計思路
簽名的目標是確保「請求未被篡改 + 來源可信 + 有效時間內唯一調用」。其基本設計流程如下:
請求參數說明
參數名 | 說明 |
| 接口調用方唯一標識 |
| 請求時間戳,用于防止過期請求 |
| 隨機字符串,確保請求唯一性 |
| 簽名值,由后端根據參數與秘鑰生成 |
簽名生成算法
簽名算法一般為:
sign = MD5(按 key 排序后的參數字符串 + appSecret)
參數拼接規則舉例:
appId=123&nonce=xyz&t=1710001234&data=xxx&appSecret=abcDEF123
接口限流與重放攻擊防護
限流實現(Redis 簡單計數法)
String key = "rate_limit:" + normalizedPath + ":" + getClientIp(request);
Long count = redisTemplate.opsForValue().increment(key);
if (count == 1) {
redisTemplate.expire(key, 10, TimeUnit.SECONDS);
}
if (count > 5) {
throw new ApiException("請求過于頻繁,請稍后再試");
}
重放防護(基于 nonce + timestamp)
String nonceKey = "nonce_cache:" + appId + ":" + nonce;
Boolean success = redisTemplate.opsForValue().setIfAbsent(nonceKey, "1", 5, TimeUnit.MINUTES);
if (Boolean.FALSE.equals(success)) {
throw new ApiException("重復請求被攔截");
}
Spring Boot + 自定義注解 + 攔截器實現簽名校驗
接下來我們通過完整代碼實現接口簽名機制,確保項目中可直接落地。
步驟 1:定義簽名校驗注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ApiSign {
boolean required() default true;
}
步驟 2:創建攔截器處理邏輯
@Component
public class ApiSecurityInterceptor implements HandlerInterceptor {
@Autowired
private RedisTemplate<String, String> redisTemplate;
private static final long EXPIRE_TIME = 5 * 60; // 5分鐘
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (!(handler instanceof HandlerMethod)) return true;
HandlerMethod method = (HandlerMethod) handler;
ApiSign apiSign = method.getMethodAnnotation(ApiSign.class);
if (apiSign == null || !apiSign.required()) return true;
// 提取參數
String appId = request.getParameter("appId");
String sign = request.getParameter("sign");
String nonce = request.getParameter("nonce");
String timestamp = request.getParameter("timestamp");
if (StringUtils.isAnyBlank(appId, sign, nonce, timestamp)) {
throw new ApiException("簽名參數不完整");
}
// 校驗時間戳
long currentTime = System.currentTimeMillis() / 1000;
if (Math.abs(currentTime - Long.parseLong(timestamp)) > EXPIRE_TIME) {
throw new ApiException("請求時間已過期");
}
// 重放校驗
String nonceKey = "nonce_cache:" + appId + ":" + nonce;
if (Boolean.FALSE.equals(redisTemplate.opsForValue().setIfAbsent(nonceKey, "1", EXPIRE_TIME, TimeUnit.SECONDS))) {
throw new ApiException("重復請求被拒絕");
}
// 簽名驗證
Map<String, String[]> parameterMap = request.getParameterMap();
String calculatedSign = SignUtils.calculateSign(parameterMap, getAppSecret(appId));
if (!sign.equalsIgnoreCase(calculatedSign)) {
throw new ApiException("簽名校驗失敗");
}
return true;
}
private String getAppSecret(String appId) {
// 實際項目中建議從數據庫或配置中心加載
return "secretFor_" + appId;
}
}
步驟 3:簽名工具類封裝
public class SignUtils {
public static String calculateSign(Map<String, String[]> params, String appSecret) {
SortedMap<String, String> sortedParams = new TreeMap<>();
for (Map.Entry<String, String[]> entry : params.entrySet()) {
if ("sign".equalsIgnoreCase(entry.getKey())) continue;
sortedParams.put(entry.getKey(), entry.getValue()[0]);
}
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
sb.append("appSecret=").append(appSecret);
return DigestUtils.md5DigestAsHex(sb.toString().getBytes(StandardCharsets.UTF_8)).toUpperCase();
}
}
步驟 4:配置攔截器生效
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private ApiSecurityInterceptor apiSecurityInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(apiSecurityInterceptor)
.addPathPatterns("/api/**");
}
}
步驟 5:接口使用方式示例
@GetMapping("/api/secure/data")
@ApiSign
public Result<String> getSecureData() {
return Result.success("這是簽名驗證通過的數據");
}
請求調用流程說明
- 調用方生成帶簽名的請求;
- 請求通過限流判斷 → 重放判斷 → 參數完整性校驗;
- 后端根據參數生成服務端簽名與客戶端簽名對比;
- 簽名一致放行,失敗則拒絕。
總結
本方案結合 Spring Boot 提供了一套輕量、可擴展的接口安全保護機制:
功能點 | 技術實現 |
簽名校驗 | 自定義注解 + 攔截器 + 參數排序 + MD5 簽名 |
防重放 | Redis 緩存 |
限流 | Redis 計數器,單位時間請求次數限制 |
易用性 | 注解式接入,低侵入、接口層無需重復代碼 |
可擴展性 | 可集成 AES 加密、IP 白名單、權限控制等高級能力 |
適用于中臺接口、對接系統、開放平臺等場景。可以作為統一接口安全網關的重要組成部分,也可獨立部署在 Spring Boot 服務中。