SpringBoot實(shí)現(xiàn)防篡改防重放的操作步驟
第一步:環(huán)境搭建——給你的接口項(xiàng)目打個(gè)底
首先,我們需要準(zhǔn)備好開發(fā)環(huán)境,并安裝必要的依賴!
1.1 創(chuàng)建SpringBoot項(xiàng)目
# 使用Spring Initializr快速創(chuàng)建項(xiàng)目 mvn archetype:generate -DgroupId=com.example -DartifactId=SecureAPI -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false cd SecureAPI
1.2 添加依賴
<dependencies>
<!-- Spring Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Hmac加密 -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.16.0</version>
</dependency>
<!-- Lombok(簡(jiǎn)化代碼) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
1.3 配置Redis
spring:
redis:
host: localhost
port: 6379
第二步:傳統(tǒng)方法——“裸奔接口”的慘痛教訓(xùn)
先來看看“零防護(hù)接口”的漏洞案例,對(duì)比之后你會(huì)更珍惜安全機(jī)制!
2.1 錯(cuò)誤方法一:純明文傳輸(失敗案例)
// 未加密的接口示例
@RestController
public class UserController {
@GetMapping("/user")
public String getUser(@RequestParam String username) {
return "Hello, " + username; // 黑客可輕易修改username參數(shù)!
}
}
2.2 錯(cuò)誤方法二:無(wú)時(shí)間戳驗(yàn)證
// 未防重放的接口示例
@PostMapping("/transfer")
public String transferMoney(@RequestParam String amount) {
// 黑客可重復(fù)發(fā)送請(qǐng)求,多次轉(zhuǎn)賬!
return "Transfer " + amount + "成功!";
}
疑問來了:為什么這兩種方法不行?
- 明文傳輸:參數(shù)易被篡改,攻擊者可直接修改。
- 無(wú)時(shí)間戳驗(yàn)證:攻擊者可重放請(qǐng)求,導(dǎo)致重復(fù)操作。
第三步:推薦方法一——參數(shù)加密與簽名:讓接口“穿上防彈衣”!
用HMAC-SHA256實(shí)現(xiàn)參數(shù)簽名,確保數(shù)據(jù)未被篡改!
3.1 客戶端簽名生成(JavaScript示例)
// 前端生成簽名
function generateSign(params, secretKey) {
// 1. 參數(shù)按字典序排序
const sortedParams = Object.keys(params)
.sort()
.map(key => `${key}=${params[key]}`)
.join('&');
// 2. 使用HMAC-SHA256生成簽名
const hmac = CryptoJS.HmacSHA256(sortedParams, secretKey);
return hmac.toString(CryptoJS.enc.Hex);
}
// 示例調(diào)用
const params = { username: 'alice', timestamp: Date.now() };
const sign = generateSign(params, 'your-secret-key');
3.2 服務(wù)端簽名驗(yàn)證(Java代碼)
@Component
public class SignatureValidator {
private final String secretKey = "your-secret-key";
public boolean validateSignature(HttpServletRequest request) {
// 1. 獲取請(qǐng)求參數(shù)和簽名
Map<String, String> params = getParams(request);
String sign = request.getHeader("Sign");
// 2. 重新生成簽名
String sortedParams = params.entrySet().stream()
.sorted(Comparator.comparing(Map.Entry::getKey))
.map(entry -> entry.getKey() + "=" + entry.getValue())
.collect(Collectors.joining("&"));
String generatedSign = HmacUtils.hmacSha256Hex(secretKey, sortedParams);
// 3. 對(duì)比簽名
return sign.equals(generatedSign);
}
private Map<String, String> getParams(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
Enumeration<String> paramNames = request.getParameterNames();
while (paramNames.hasMoreElements()) {
String paramName = paramNames.nextElement();
params.put(paramName, request.getParameter(paramName));
}
return params;
}
}
3.3 過濾器集成
@Component
public class SignatureFilter implements Filter {
@Autowired
private SignatureValidator validator;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
HttpServletRequest req = (HttpServletRequest) request;
if (!validator.validateSignature(req)) {
throw new RuntimeException("簽名驗(yàn)證失??!參數(shù)被篡改");
}
chain.doFilter(request, response);
}
}
第四步:推薦方法二——時(shí)間戳與Redis防重放:讓接口“時(shí)間刺客”無(wú)處遁形!
用時(shí)間戳+Redis記錄nonce,防止重復(fù)請(qǐng)求!
4.1 時(shí)間戳驗(yàn)證邏輯
public boolean validateTimestamp(HttpServletRequest request) {
long currentTime = System.currentTimeMillis();
long requestTime = Long.parseLong(request.getHeader("Timestamp"));
// 允許時(shí)間差60秒
return (currentTime - requestTime) <= 60_000;
}
4.2 Redis記錄nonce(唯一標(biāo)識(shí))
public boolean validateNonce(HttpServletRequest request) {
String nonce = request.getHeader("Nonce");
// 使用Redis記錄已使用的nonce,有效期60秒
String key = "nonce:" + nonce;
if (redisTemplate.hasKey(key)) {
return false; // 已存在,說明是重放請(qǐng)求
}
redisTemplate.opsForValue().set(key, "used", 60, TimeUnit.SECONDS);
return true;
}
4.3 完整過濾器實(shí)現(xiàn)
@Component
public class SecurityFilter implements Filter {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
HttpServletRequest req = (HttpServletRequest) request;
// 1. 驗(yàn)證簽名
if (!validateSignature(req)) {
throw new RuntimeException("簽名驗(yàn)證失??!");
}
// 2. 驗(yàn)證時(shí)間戳
if (!validateTimestamp(req)) {
throw new RuntimeException("時(shí)間戳超時(shí)!");
}
// 3. 驗(yàn)證nonce
if (!validateNonce(req)) {
throw new RuntimeException("重復(fù)請(qǐng)求!防重放失敗");
}
chain.doFilter(request, response);
}
}
第五步:推薦方法三——HTTPS加密傳輸:給接口“穿金戴銀”!
用HTTPS加密傳輸,確保數(shù)據(jù)不被竊?。?/p>
5.1 配置HTTPS
server:
port: 8443
ssl:
key-store: classpath:keystore.p12
key-store-password: your-password
key-store-type: PKCS12
5.2 生成密鑰庫(kù)(Java命令)
keytool -genkeypair -alias mykey -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 365
第六步:實(shí)戰(zhàn)案例——從零到有實(shí)現(xiàn)一個(gè)“銀行轉(zhuǎn)賬接口”
整合所有技術(shù),實(shí)現(xiàn)一個(gè)安全的轉(zhuǎn)賬接口!
6.1 接口定義
@RestController
public class TransferController {
@PostMapping("/transfer")
public String transfer(@RequestParam String amount, @RequestParam String nonce) {
// 實(shí)際轉(zhuǎn)賬邏輯(此處省略)
return "轉(zhuǎn)賬" + amount + "元成功!";
}
}
6.2 客戶端調(diào)用示例(JavaScript)
const params = {
amount: "1000",
timestamp: Date.now(),
nonce: Math.random().toString(36).substr(2)
};
const sign = generateSign(params, 'your-secret-key');
fetch('/transfer', {
method: 'POST',
headers: {
'Sign': sign,
'Timestamp': params.timestamp,
'Nonce': params.nonce
},
body: new URLSearchParams(params)
});
第七步:隱藏技巧——分布式環(huán)境下時(shí)間同步與nonce全局管理
用NTP同步時(shí)間和Redis集群保證分布式部署!
7.1 NTP時(shí)間同步(Linux命令)
sudo ntpdate pool.ntp.org
7.2 Redis集群配置
spring:
redis:
cluster:
nodes:
- 192.168.1.100:6379
- 192.168.1.101:6379
第八步:壓力測(cè)試——讓接口“吃雞”!
最后,用壓力測(cè)試驗(yàn)證你的安全機(jī)制是否扛得住百萬(wàn)級(jí)請(qǐng)求!
8.1 JMeter測(cè)試計(jì)劃
<TestPlan>
<ThreadGroup num_threads="1000">
<HTTPSamplerProxy>
<HeaderManager>
<Header>Sign=your-sign</Header>
<Header>Timestamp=1623456789</Header>
<Header>Nonce=random-123</Header>
</HeaderManager>
<Path>/transfer</Path>
</HTTPSamplerProxy>
</ThreadGroup>
</TestPlan>
從“裸奔接口”到“黑客退退退”,讓安全機(jī)制“秒變”神器
經(jīng)過這8個(gè)步驟的學(xué)習(xí),我們不僅掌握了參數(shù)簽名、時(shí)間戳防重放和HTTPS加密,還了解了如何在分布式環(huán)境下實(shí)現(xiàn)全局安全控制。無(wú)論是電商支付接口還是物聯(lián)網(wǎng)控制接口,這些技巧都能讓你的SpringBoot項(xiàng)目像“鋼鐵俠”一樣堅(jiān)不可摧!
以上就是SpringBoot防篡改防重放的操作步驟的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot防篡改防重放的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringBoot項(xiàng)目整合mybatis的方法步驟與實(shí)例
今天小編就為大家分享一篇關(guān)于SpringBoot項(xiàng)目整合mybatis的方法步驟與實(shí)例,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-03
IDEA 2020.2 +Gradle 6.6.1 + Spring Boot 2.3.4 創(chuàng)建多模塊項(xiàng)目的超詳細(xì)教程
這篇文章主要介紹了IDEA 2020.2 +Gradle 6.6.1 + Spring Boot 2.3.4 創(chuàng)建多模塊項(xiàng)目的教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
java 數(shù)據(jù)的加密與解密普遍實(shí)例代碼
本篇文章介紹了一個(gè)關(guān)于密鑰查詢的jsp文件簡(jiǎn)單實(shí)例代碼,需要的朋友可以參考下2017-04-04
java 取交集方法retainAll的實(shí)現(xiàn)
這篇文章主要介紹了java 取交集方法retainAll的實(shí)現(xiàn)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
詳解Spring Boot 中實(shí)現(xiàn)定時(shí)任務(wù)的兩種方式
這篇文章主要介紹了Spring Boot 中實(shí)現(xiàn)定時(shí)任務(wù)的兩種方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
springboot的SpringPropertyAction事務(wù)屬性源碼解讀
這篇文章主要介紹了springboot的SpringPropertyAction事務(wù)屬性源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
淺析Bean?Searcher?與?MyBatis?Plus?區(qū)別介紹
Bean?Searcher號(hào)稱任何復(fù)雜的查詢都可以一行代碼搞定,但?Mybatis?Plus?似乎也有類似的動(dòng)態(tài)查詢功能,最近火起的?Bean?Searcher?與?MyBatis?Plus?倒底有啥區(qū)別?帶著這個(gè)問題一起通過本文學(xué)習(xí)下吧2022-05-05
詳解如何配置springboot跳轉(zhuǎn)html頁(yè)面
這篇文章主要介紹了詳解如何配置springboot跳轉(zhuǎn)html頁(yè)面,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
Spring AOP使用@Aspect注解 面向切面實(shí)現(xiàn)日志橫切的操作
這篇文章主要介紹了Spring AOP使用@Aspect注解 面向切面實(shí)現(xiàn)日志橫切的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06

