成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

實戰出真知!SpringBoot 接口級防護:限流、重放攻擊與簽名機制全解析

開發 前端
本文將基于 Spring Boot 框架,手把手實現一套可落地的接口安全防護機制,涵蓋簽名驗證、防重放、限流控制等核心能力,適用于 B 端開放接口、系統對接場景。

在當今數字化服務廣泛開放的背景下,后端接口往往暴露在公網之下,極易成為攻擊者的突破口。接口調用的重放攻擊、參數偽造、暴力請求等問題屢見不鮮,嚴重威脅服務安全與數據完整性。

本文將基于 Spring Boot 框架,手把手實現一套可落地的接口安全防護機制,涵蓋簽名驗證、防重放、限流控制等核心能力,適用于 B 端開放接口、系統對接場景。

接口簽名驗證設計思路

簽名的目標是確保「請求未被篡改 + 來源可信 + 有效時間內唯一調用」。其基本設計流程如下:

請求參數說明

參數名

說明

appId

接口調用方唯一標識

timestamp

請求時間戳,用于防止過期請求

nonce

隨機字符串,確保請求唯一性

sign

簽名值,由后端根據參數與秘鑰生成

簽名生成算法

簽名算法一般為:

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("這是簽名驗證通過的數據");
}

請求調用流程說明

  1. 調用方生成帶簽名的請求;
  2. 請求通過限流判斷 → 重放判斷 → 參數完整性校驗;
  3. 后端根據參數生成服務端簽名與客戶端簽名對比;
  4. 簽名一致放行,失敗則拒絕。

總結

本方案結合 Spring Boot 提供了一套輕量、可擴展的接口安全保護機制:

功能點

技術實現

簽名校驗

自定義注解 + 攔截器 + 參數排序 + MD5 簽名

防重放

Redis 緩存 nonce,設定過期時間

限流

Redis 計數器,單位時間請求次數限制

易用性

注解式接入,低侵入、接口層無需重復代碼

可擴展性

可集成 AES 加密、IP 白名單、權限控制等高級能力

適用于中臺接口、對接系統、開放平臺等場景。可以作為統一接口安全網關的重要組成部分,也可獨立部署在 Spring Boot 服務中。

責任編輯:武曉燕 來源: 路條編程
相關推薦

2025-06-03 04:10:00

2024-10-08 08:26:43

2011-04-06 10:36:21

2025-06-26 02:11:00

2025-02-26 00:28:01

2011-04-06 10:23:46

2011-04-06 10:31:53

2021-03-30 10:46:42

SpringBoot計數器漏桶算法

2017-07-14 17:41:20

2024-07-18 09:29:02

2025-05-12 08:24:04

高并發流量系統

2015-01-20 09:35:52

2014-11-18 09:35:14

2011-04-06 10:03:16

2022-03-02 11:42:06

勒索軟件網絡安全

2020-12-30 10:22:08

物聯網安全攻擊防護防火墻

2013-05-13 17:49:26

2013-04-26 09:45:35

2015-08-27 09:15:35

2013-12-23 10:14:36

虛擬網絡
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久一级大片 | 久久精品一区二区三区四区 | 操操日| 亚洲黄色片免费观看 | 中文字幕亚洲精品在线观看 | 国产在线一区二区三区 | 国产探花在线观看视频 | 国内精品久久久久 | 一级国产精品一级国产精品片 | 国产一区免费视频 | 日日爱视频 | 一区在线视频 | 天天色天天射天天干 | 国产精品久久一区二区三区 | 午夜二区 | 久久久久久久国产 | 波多野结衣一二三区 | 国产精品夜间视频香蕉 | 国产精品日韩一区二区 | 一区二区三区韩国 | 国产做a爱片久久毛片 | 九色 在线| 麻豆精品一区二区三区在线观看 | 亚洲一区二区三区视频在线 | 亚洲 欧美 日韩在线 | 日韩高清一区二区 | 国产精品国产精品国产专区不片 | 一区二区三区四区在线 | 啪啪av| 成人国产a | 偷拍亚洲色图 | 日本精品久久久久 | 青青草精品视频 | 91精品国产综合久久婷婷香蕉 | 久久aⅴ乱码一区二区三区 亚洲欧美综合精品另类天天更新 | 久草a√| 中文字幕一区二区三区乱码图片 | 欧美一级片在线播放 | 久久国产日韩欧美 | 免费看a| 精品乱码一区二区三四区视频 |