基于SpringBoot實(shí)現(xiàn)防盜鏈功能
一、防盜鏈概念
防盜鏈?zhǔn)且环N通過(guò)限制資源訪問(wèn)來(lái)源的技術(shù),通常通過(guò)檢查 HTTP 請(qǐng)求頭中的 Referer 字段來(lái)實(shí)現(xiàn)。如果請(qǐng)求的來(lái)源不是允許的域名,則拒絕該請(qǐng)求。除此之外,還可以結(jié)合 Token 和時(shí)間戳進(jìn)一步提高安全性,確保鏈接只能在一定時(shí)間內(nèi)有效。
二、防盜鏈原理
- Referer 校驗(yàn):
- HTTP Referer 是瀏覽器在發(fā)送請(qǐng)求時(shí)附加的字段,用于標(biāo)明請(qǐng)求的來(lái)源頁(yè)面。
- 服務(wù)器可以通過(guò)檢查 Referer 是否屬于信任的域名,拒絕其他來(lái)源的訪問(wèn)請(qǐng)求。
- Token 驗(yàn)證:
- 服務(wù)器為合法請(qǐng)求生成帶簽名的訪問(wèn)鏈接(包含 Token),客戶(hù)端訪問(wèn)時(shí)攜帶該 Token。
- 服務(wù)器通過(guò)驗(yàn)證 Token 是否正確來(lái)判斷請(qǐng)求合法性。
- 時(shí)間限制:
- 通過(guò)在請(qǐng)求中附帶時(shí)間戳參數(shù),限制鏈接的有效期。
- 服務(wù)器校驗(yàn)請(qǐng)求的時(shí)間戳與當(dāng)前時(shí)間的差值,超出范圍的請(qǐng)求將被拒絕。
通過(guò)以上三種機(jī)制,可以顯著提高資源防盜鏈的安全性。
三、項(xiàng)目結(jié)構(gòu)
以下是示例項(xiàng)目的目錄結(jié)構(gòu):
src
├── main
│ ├── java
│ │ └── com.demo
│ │ ├── DemoApplication.java
│ │ ├── filter
│ │ │ ├── StaticResourceFilter.java
│ │ │ ├── TokenValidator.java
│ │ │ └── TimeValidator.java
│ └── resources
│ └── static
│ └── images
└──711815.jpeg
四、核心代碼實(shí)現(xiàn)
1. 主應(yīng)用程序入口
package com.et;
import com.et.filter.StaticResourceFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
public FilterRegistrationBean<StaticResourceFilter> staticResourceFilter() {
FilterRegistrationBean<StaticResourceFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new StaticResourceFilter());
registrationBean.addUrlPatterns("/images/*");
return registrationBean;
}
}
2. 靜態(tài)資源訪問(wèn)過(guò)濾器
package com.et.filter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class StaticResourceFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// validate Referer
String referer = httpRequest.getHeader("Referer");
String allowedDomain = "http://localhost:8088";
if (referer == null || !referer.startsWith(allowedDomain)) {
httpResponse.getWriter().write("403 Forbidden: Hotlinking not allowed");
return;
}
// validate Token
if (!TokenValidator.validateToken(httpRequest, httpResponse)) {
return;
}
// validate Timestamp
if (!TimeValidator.validateTimestamp(httpRequest, httpResponse)) {
return;
}
chain.doFilter(request, response);
}
}
3. Token 驗(yàn)證工具
package com.et.filter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class TokenValidator {
public static boolean validateToken(HttpServletRequest request, HttpServletResponse response) throws IOException {
String token = request.getParameter("token");
String validToken = "your-predefined-token"; //set your predefined token here
if (token == null || !token.equals(validToken)) {
response.getWriter().write("403 Forbidden: Invalid Token");
return false;
}
return true;
}
}
4. 時(shí)間限制驗(yàn)證工具
package com.et.filter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Instant;
public class TimeValidator {
private static final long ALLOWED_TIME_DIFF = 300; // offset in seconds( 300 seconds)
public static boolean validateTimestamp(HttpServletRequest request, HttpServletResponse response) throws IOException {
String timestampStr = request.getParameter("timestamp");
if (timestampStr == null) {
response.getWriter().write("403 Forbidden: Missing Timestamp");
return false;
}
try {
long timestamp = Long.parseLong(timestampStr);
long currentTimestamp = Instant.now().getEpochSecond();
if (Math.abs(currentTimestamp - timestamp) > ALLOWED_TIME_DIFF) {
response.getWriter().write("403 Forbidden: Timestamp Expired");
return false;
}
} catch (NumberFormatException e) {
response.getWriter().write("403 Forbidden: Invalid Timestamp");
return false;
}
return true;
}
}
5. 靜態(tài)資源示例
將一個(gè)圖片文件711815.jpeg 放入 src/main/resources/static/images 文件夾中。
以上只是一些關(guān)鍵代碼。
五、測(cè)試方式
啟動(dòng) Spring Boot 項(xiàng)目。
測(cè)試訪問(wèn)圖片資源:
curl -X GET "http://localhost:8088/static/example.jpg?token=your-predefined-token×tamp=$(date +%s)" -H "Referer: http://localhost:8088"
檢查以下情況:
- 如果 Referer 不正確,返回
403 Forbidden: Hotlinking not allowed。 - 如果 Token 無(wú)效,返回
403 Forbidden: Invalid Token。 - 如果時(shí)間戳超時(shí),返回
403 Forbidden: Timestamp Expired。
- 如果 Referer 不正確,返回
通過(guò)本文,您可以了解如何通過(guò) Referer 校驗(yàn)、Token 驗(yàn)證和時(shí)間限制實(shí)現(xiàn)資源防盜鏈保護(hù)。如果有其他問(wèn)題或需求,歡迎進(jìn)一步探討!
到此這篇關(guān)于基于SpringBoot實(shí)現(xiàn)防盜鏈功能的文章就介紹到這了,更多相關(guān)SpringBoot防盜鏈內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot 1.5.2 集成kafka的簡(jiǎn)單例子
本篇文章主要介紹了springboot 1.5.2 集成kafka的簡(jiǎn)單例子 ,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11
java實(shí)現(xiàn)傾斜水印鋪滿(mǎn)整張圖
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)傾斜水印鋪滿(mǎn)整張圖的具體代碼,教大家如何控制水印之間的空隙,感興趣的小伙伴們可以參考一下2016-06-06
gateway和jwt網(wǎng)關(guān)認(rèn)證實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了gateway和jwt網(wǎng)關(guān)認(rèn)證實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11
Java Stream 流實(shí)現(xiàn)合并操作示例
這篇文章主要介紹了Java Stream 流實(shí)現(xiàn)合并操作,結(jié)合實(shí)例形式詳細(xì)分析了Java Stream 流實(shí)現(xiàn)合并操作原理與相關(guān)注意事項(xiàng),需要的朋友可以參考下2020-05-05
SpringBoot如何讀取xml配置bean(@ImportResource)
這篇文章主要介紹了SpringBoot如何讀取xml配置bean(@ImportResource),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
Kafka是什么及如何使用SpringBoot對(duì)接Kafka(最新推薦)
這篇文章主要介紹了Kafka是什么,以及如何使用SpringBoot對(duì)接Kafka,今天我們通過(guò)一個(gè)Demo講解了在SpringBoot中如何對(duì)接Kafka,也介紹了下關(guān)鍵類(lèi)?KafkaTemplate,需要的朋友可以參考下2023-11-11

