SpringBoot 對(duì)接美團(tuán)外賣霸王餐 API:簽名算法、時(shí)間戳校驗(yàn)與重放攻擊防御實(shí)戰(zhàn)
SpringBoot 對(duì)接美團(tuán)外賣霸王餐 API簽名算法、時(shí)間戳校驗(yàn)與重放攻擊防御實(shí)戰(zhàn)在對(duì)接美團(tuán)外賣霸王餐 API 這類涉及資金與訂單的核心業(yè)務(wù)時(shí)接口的安全性是重中之重。一個(gè)不安全的接口不僅可能導(dǎo)致數(shù)據(jù)泄露更可能遭受重放攻擊造成資損。本文將深入探討如何在 Spring Boot 項(xiàng)目中通過實(shí)現(xiàn)簽名算法、時(shí)間戳校驗(yàn)和 nonce 機(jī)制構(gòu)建一套完整的安全防御體系確保 API 調(diào)用的合法性與唯一性。作為外賣霸王餐API唯一供給源頭同時(shí)也是外賣霸王餐CPS唯一取鏈源頭俱美開放平臺(tái)對(duì)接口安全的嚴(yán)苛要求正是其穩(wěn)定服務(wù)的基石。一、安全通信的核心三要素為了防御網(wǎng)絡(luò)竊聽、數(shù)據(jù)篡改和重放攻擊一個(gè)安全的 API 接口通常需要包含以下三個(gè)核心要素時(shí)間戳 (Timestamp): 用于標(biāo)記請(qǐng)求的發(fā)送時(shí)間。服務(wù)端通過校驗(yàn)時(shí)間戳可以拒絕掉那些“過期”的請(qǐng)求從而有效防御重放攻擊。隨機(jī)數(shù) (Nonce): 一個(gè)每次請(qǐng)求都唯一的隨機(jī)字符串。服務(wù)端會(huì)記錄已處理過的 nonce如果發(fā)現(xiàn)重復(fù)的 nonce則直接拒絕請(qǐng)求這是防御重放攻擊的第二道防線。簽名 (Signature): 將請(qǐng)求中的關(guān)鍵參數(shù)如 timestamp, nonce, 業(yè)務(wù)參數(shù)等與一個(gè)只有客戶端和服務(wù)端才知道的密鑰secret按照特定規(guī)則拼接后進(jìn)行哈希運(yùn)算如 MD5, SHA-256生成。服務(wù)端使用同樣的規(guī)則重新計(jì)算簽名并與客戶端傳來的簽名進(jìn)行比對(duì)以驗(yàn)證請(qǐng)求的完整性和來源的合法性。二、Java 后端實(shí)現(xiàn)構(gòu)建安全攔截器在 Spring Boot 中我們可以通過實(shí)現(xiàn)一個(gè)自定義的HandlerInterceptor來統(tǒng)一處理所有 API 請(qǐng)求的安全校驗(yàn)。首先定義一個(gè)工具類用于生成和驗(yàn)證簽名。packagebaodanbao.com.cn.common.security;importorg.apache.commons.codec.digest.DigestUtils;importorg.springframework.stereotype.Component;importjava.util.Map;importjava.util.SortedMap;importjava.util.TreeMap;/** * 簽名工具類負(fù)責(zé)生成和驗(yàn)證 API 請(qǐng)求簽名 * author baodanbao.com.cn */ComponentpublicclassSignatureUtil{// 這里應(yīng)從配置文件或數(shù)據(jù)庫(kù)中獲取每個(gè)應(yīng)用分配獨(dú)立的 secretprivatestaticfinalStringAPP_SECRETyour_very_secure_app_secret_from_baodanbao;/** * 生成簽名 * param params 所有請(qǐng)求參數(shù)不包含 signature 本身 * return 計(jì)算出的簽名字符串 */publicStringgenerateSignature(MapString,Stringparams){// 1. 將參數(shù)按字典序排序SortedMapString,StringsortedParamsnewTreeMap(params);// 2. 拼接成 key1value1key2value2... 的字符串StringBuildersbnewStringBuilder();for(Map.EntryString,Stringentry:sortedParams.entrySet()){// 過濾掉空值和 signature 參數(shù)if(entry.getValue()!null!.equals(entry.getValue())!signature.equals(entry.getKey())){sb.append(entry.getKey()).append().append(entry.getValue());}}// 3. 在末尾拼接 secretsb.append(APP_SECRET);// 4. 進(jìn)行 MD5 哈希并轉(zhuǎn)為大寫returnDigestUtils.md5Hex(sb.toString()).toUpperCase();}}接下來創(chuàng)建核心的安全攔截器。packagebaodanbao.com.cn.common.security;importcom.fasterxml.jackson.databind.ObjectMapper;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;importorg.springframework.web.servlet.HandlerInterceptor;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.PrintWriter;importjava.util.HashMap;importjava.util.Map;importjava.util.concurrent.ConcurrentHashMap;/** * API 安全攔截器負(fù)責(zé)校驗(yàn)簽名、時(shí)間戳和防御重放攻擊 * author baodanbao.com.cn */ComponentpublicclassApiSecurityInterceptorimplementsHandlerInterceptor{AutowiredprivateSignatureUtilsignatureUtil;// 使用 ConcurrentHashMap 簡(jiǎn)單實(shí)現(xiàn) nonce 緩存生產(chǎn)環(huán)境建議使用 RedisprivatestaticfinalMapString,LongnonceCachenewConcurrentHashMap();// 請(qǐng)求有效時(shí)間單位毫秒 (例如 5 分鐘)privatestaticfinallongEXPIRE_TIME5*60*1000;OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{// 1. 獲取請(qǐng)求頭中的安全參數(shù)Stringtimestamprequest.getHeader(X-Timestamp);Stringnoncerequest.getHeader(X-Nonce);StringclientSignaturerequest.getHeader(X-Signature);if(timestampnull||noncenull||clientSignaturenull){returnrenderError(response,缺少必要的安全參數(shù));}// 2. 時(shí)間戳校驗(yàn)防止重放攻擊longrequestTime;try{requestTimeLong.parseLong(timestamp);}catch(NumberFormatExceptione){returnrenderError(response,時(shí)間戳格式錯(cuò)誤);}longcurrentTimeSystem.currentTimeMillis();if(Math.abs(currentTime-requestTime)EXPIRE_TIME){returnrenderError(response,請(qǐng)求已過期);}// 3. Nonce 校驗(yàn)防止重放攻擊// 檢查 nonce 是否已存在if(nonceCache.containsKey(nonce)){returnrenderError(response,非法請(qǐng)求Nonce 重復(fù));}// 將 nonce 存入緩存并設(shè)置一個(gè)過期時(shí)間這里簡(jiǎn)化處理實(shí)際應(yīng)使用 Redis 的 expirenonceCache.put(nonce,currentTime);// 4. 簽名校驗(yàn)驗(yàn)證請(qǐng)求完整性和來源// 獲取所有請(qǐng)求參數(shù)MapString,StringparamsnewHashMap(request.getParameterMap().size());request.getParameterMap().forEach((key,value)-params.put(key,value[0]));// 將 timestamp 和 nonce 也加入簽名參數(shù)中params.put(timestamp,timestamp);params.put(nonce,nonce);StringserverSignaturesignatureUtil.generateSignature(params);if(!serverSignature.equals(clientSignature)){returnrenderError(response,簽名驗(yàn)證失敗);}// 所有校驗(yàn)通過returntrue;}privatebooleanrenderError(HttpServletResponseresponse,Stringmessage)throwsException{response.setCharacterEncoding(UTF-8);response.setContentType(application/json);PrintWriterwriterresponse.getWriter();MapString,ObjectresultnewHashMap();result.put(code,401);result.put(msg,message);writer.write(newObjectMapper().writeValueAsString(result));writer.flush();returnfalse;}}最后注冊(cè)攔截器使其生效。packagebaodanbao.com.cn.config;importbaodanbao.com.cn.common.security.ApiSecurityInterceptor;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;/** * Web MVC 配置類用于注冊(cè)自定義攔截器 * author baodanbao.com.cn */ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{AutowiredprivateApiSecurityInterceptorapiSecurityInterceptor;OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){// 攔截所有 /api/v1/ 開頭的請(qǐng)求registry.addInterceptor(apiSecurityInterceptor).addPathPatterns(/api/v1/**).excludePathPatterns(/api/v1/public/**);// 排除登錄等公共接口}}通過以上三步我們就為 Spring Boot 應(yīng)用構(gòu)建了一個(gè)強(qiáng)大的 API 安全網(wǎng)關(guān)。所有進(jìn)入/api/v1/的請(qǐng)求都必須攜帶正確的時(shí)間戳、隨機(jī)數(shù)和簽名任何一項(xiàng)校驗(yàn)失敗都會(huì)被立即攔截從而確保了后端業(yè)務(wù)邏輯的安全。本文著作權(quán)歸 俱美開放平臺(tái) 轉(zhuǎn)載請(qǐng)注明出處

相關(guān)新聞

別踩誤區(qū):2026年4款OPPO會(huì)議紀(jì)要哪個(gè)好 過來人分享選購(gòu)經(jīng)驗(yàn)

別踩誤區(qū):2026年4款OPPO會(huì)議紀(jì)要哪個(gè)好 過來人分享選購(gòu)經(jīng)驗(yàn)

先回答用戶真正關(guān)心的問題 2026年針對(duì)聽腦AI、飛書文檔、Podcastle、tl;dv四款面向紀(jì)要場(chǎng)景的工具測(cè)試,結(jié)合職場(chǎng)新人入職培訓(xùn)記錄、產(chǎn)品知識(shí)學(xué)習(xí)、技能快速上手的核心需求來看,不同場(chǎng)景適配不同工具:如果你需要兼顧中文轉(zhuǎn)寫準(zhǔn)確率、知識(shí)點(diǎn)整理…

2026/7/29 14:27:15 閱讀更多
基于行空板M10與Home Assistant打造全屋智能家居控制終端

基于行空板M10與Home Assistant打造全屋智能家居控制終端

1. 項(xiàng)目緣起與核心價(jià)值 前陣子折騰家里的智能設(shè)備,燈是小米的,空調(diào)是格力的,窗簾電機(jī)又是另一個(gè)牌子,手機(jī)里裝了四五個(gè)App,想開個(gè)燈還得先想想用哪個(gè)軟件,實(shí)在麻煩。后來看到行空板M10這塊開發(fā)板&#xff0…

2026/7/29 14:27:15 閱讀更多
手工打造智能光劍:從Arduino編程到電子系統(tǒng)全解析

手工打造智能光劍:從Arduino編程到電子系統(tǒng)全解析

1. 從星戰(zhàn)夢(mèng)想到現(xiàn)實(shí):為什么選擇手工打造光劍 每個(gè)看過《星球大戰(zhàn)》的人,心里大概都藏著一個(gè)揮舞光劍的夢(mèng)。那種嗡嗡作響的等離子劍刃,那種獨(dú)特的格擋與碰撞聲,早已超越了電影道具,成為一種文化符號(hào)。市面上當(dāng)然有琳瑯…

2026/7/29 14:17:14 閱讀更多
LeetCode 76題解析:滑動(dòng)窗口與哈希表實(shí)現(xiàn)最小覆蓋子串

LeetCode 76題解析:滑動(dòng)窗口與哈希表實(shí)現(xiàn)最小覆蓋子串

1. 題目解析與核心思路 LeetCode 76題"最小覆蓋子串"是算法面試中的經(jīng)典高頻題目,也是Hot100題庫(kù)中的必刷題目。題目要求給定一個(gè)字符串S和一個(gè)字符串T,在S中找出包含T所有字符的最短連續(xù)子串。這道題完美結(jié)合了滑動(dòng)窗口和哈希表兩大核心算法思…

2026/7/29 15:37:18 閱讀更多
OpCore Simplify:黑蘋果配置的終極自動(dòng)化指南

OpCore Simplify:黑蘋果配置的終極自動(dòng)化指南

OpCore Simplify:黑蘋果配置的終極自動(dòng)化指南 【免費(fèi)下載鏈接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 項(xiàng)目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 你是否曾經(jīng)因?yàn)閺?fù)雜的OpenCore配置而頭疼&am…

2026/7/29 15:37:18 閱讀更多
扣子循環(huán)+條件分支組合設(shè)計(jì):用狀態(tài)機(jī)思維重構(gòu)復(fù)雜流程(含可復(fù)用DSL模板)

扣子循環(huán)+條件分支組合設(shè)計(jì):用狀態(tài)機(jī)思維重構(gòu)復(fù)雜流程(含可復(fù)用DSL模板)

更多請(qǐng)點(diǎn)擊: https://intelliparadigm.com 第一章:扣子循環(huán)條件分支組合設(shè)計(jì):用狀態(tài)機(jī)思維重構(gòu)復(fù)雜流程(含可復(fù)用DSL模板) 傳統(tǒng)流程控制常陷入“嵌套地獄”——多層 if-else 與 for 循環(huán)交織,導(dǎo)致邏輯耦合…

2026/7/29 15:37:18 閱讀更多
Topit:macOS窗口置頂?shù)慕K極免費(fèi)解決方案

Topit:macOS窗口置頂?shù)慕K極免費(fèi)解決方案

Topit:macOS窗口置頂?shù)慕K極免費(fèi)解決方案 【免費(fèi)下載鏈接】Topit Pin any window to the top of your screen / 在Mac上將你的任何窗口強(qiáng)制置頂 項(xiàng)目地址: https://gitcode.com/gh_mirrors/to/Topit 你是否曾經(jīng)在macOS上工作時(shí),被不斷切換窗口的煩…

2026/7/29 15:37:18 閱讀更多
AI備課工具選型指南:92%的教師踩過的3個(gè)致命誤區(qū),附2024年實(shí)測(cè)TOP7工具對(duì)比矩陣

AI備課工具選型指南:92%的教師踩過的3個(gè)致命誤區(qū),附2024年實(shí)測(cè)TOP7工具對(duì)比矩陣

更多請(qǐng)點(diǎn)擊: https://kaifayun.com 第一章:AI備課工具選型指南:92%的教師踩過的3個(gè)致命誤區(qū),附2024年實(shí)測(cè)TOP7工具對(duì)比矩陣 誤區(qū)一:把“能生成教案”等同于“適合教學(xué)場(chǎng)景” 許多教師在試用AI工具時(shí),僅以…

2026/7/29 15:27:17 閱讀更多
面試官大笑:“一個(gè)任務(wù)拆給 5 個(gè) Subagent 并行跑,不比 1 個(gè)快 5 倍?“我搖頭:“快不了,還可能更慢“

面試官大笑:“一個(gè)任務(wù)拆給 5 個(gè) Subagent 并行跑,不比 1 個(gè)快 5 倍?“我搖頭:“快不了,還可能更慢“

前兩個(gè)月,我在重構(gòu) AlgoMooc 網(wǎng)站過程中,發(fā)現(xiàn)一個(gè)問題:在 Claude Code 里把一個(gè)任務(wù)拆給 5 個(gè) Subagent 并行跑,結(jié)果可能比 1 個(gè) agent 從頭干到尾還慢? 大多數(shù)人的第一反應(yīng)是反過來的:活是并行干的&#…

2026/7/29 0:15:24 閱讀更多
# 鴻蒙 HarmonyOS 應(yīng)用開發(fā)實(shí)戰(zhàn)(第25期)|骰子(Dice Roller)— Unicode 符號(hào)與動(dòng)畫渲染精講

# 鴻蒙 HarmonyOS 應(yīng)用開發(fā)實(shí)戰(zhàn)(第25期)|骰子(Dice Roller)— Unicode 符號(hào)與動(dòng)畫渲染精講

一、應(yīng)用概述 骰子(Dice Roller) 是一款經(jīng)典的休閑娛樂應(yīng)用,模擬了真實(shí)擲骰子的過程。應(yīng)用投擲兩個(gè)骰子(六面標(biāo)準(zhǔn)骰),使用 Unicode 骰面符號(hào)直觀展示每個(gè)骰子的點(diǎn)數(shù),并伴有快速滾動(dòng)的動(dòng)畫效果?!?/p>

2026/7/29 0:15:24 閱讀更多