Java防止非法盜鏈的幾種解決方案
非法盜鏈概述
非法盜鏈指的是在未獲得授權(quán)的情況下,將別人的資源(如圖片、視頻等)直接鏈接到自己的網(wǎng)站上,從而消耗他人的帶寬和流量,并影響原始資源的安全性。
HTTP Referer請(qǐng)求頭驗(yàn)證
通過(guò)檢查HTTP頭部中的Referer字段,判斷請(qǐng)求來(lái)源是否合法。只允許來(lái)自特定域名或IP地址的請(qǐng)求才能訪問(wèn)資源。這種方法較容易實(shí)施,不過(guò)存在一定的偽造風(fēng)險(xiǎn)。
Spring MVC項(xiàng)目
創(chuàng)建RefererFilter類(lèi)實(shí)現(xiàn)Filter接口并重寫(xiě)3個(gè)方法,實(shí)現(xiàn)過(guò)濾邏輯。
在處理請(qǐng)求時(shí)判斷請(qǐng)求頭中的Referer字段,然后通過(guò)字符串比較或正則匹配可以判斷請(qǐng)求來(lái)源是否合法,如果不合法可以返回錯(cuò)誤信息或重定向到其他頁(yè)面。
public class RefererFilter implements Filter {
? ? @Override
? ? public void init(FilterConfig filterConfig) throws ServletException {
?? ??? ?System.out.println("初始化方法...");
? ? }
? ? /**
? ? ?* @param request
? ? ?* @param response
? ? ?* @param chain
? ? ?*/
? ? @Override
? ? public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
??? ? ? ?System.out.println("攔截請(qǐng)求...");
? ? ? ? HttpServletRequest req = (HttpServletRequest) request;
? ? ? ? HttpServletResponse res = (HttpServletResponse) response;
? ? ? ? //每次請(qǐng)求來(lái)源
? ? ? ? String referer = req.getHeader("referer");
? ? ? ? //獲取請(qǐng)求地址
? ? ? ? String serverName = req.getServerName();
? ? ? ? System.out.println("referer:" + referer + "---serverName" + serverName);
? ? ? ? if (referer == null || !referer.contains(serverName)) {
? ? ? ? ? ? req.getRequestDispatcher("/static/images/error.png").forward(req, res);
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? //放行
? ? ? ? chain.doFilter(req, res);
? ? }
? ? @Override
? ? public void destroy() {
?? ??? ?System.out.println("銷(xiāo)毀請(qǐng)求...");
? ? }
}web.xml配置過(guò)濾器
<filter>
<filter-name>RefererFilter</filter-name>
<filter-class>cn.ybzy.demo.fileter.RefererFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RefererFilter</filter-name>
<url-pattern>/static/images/*</url-pattern>
</filter-mapping>Spring Boot項(xiàng)目
創(chuàng)建一個(gè)攔截器來(lái)對(duì) HTTP Referer 請(qǐng)求頭進(jìn)行驗(yàn)證
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class RefererInterceptor implements HandlerInterceptor {
? ? // 允許的 referer
? ? private static final String ALLOWED_REFERER = "https://www.your-domain.com";
? ? @Override
? ? public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
? ? ? ? String referer = request.getHeader("Referer");
? ? ? ? // 如果請(qǐng)求頭中的 Referer 不是允許的域名,則返回 403 錯(cuò)誤
? ? ? ? if (referer == null || !referer.startsWith(ALLOWED_REFERER)) {
? ? ? ? ? ? response.sendError(HttpServletResponse.SC_FORBIDDEN);
? ? ? ? ? ? return false;
? ? ? ? }
? ? ? ? // 否則放行
? ? ? ? return true;
? ? }
}通過(guò) WebMvcConfigurer 接口和 addInterceptors 方法注冊(cè)了名為 RefererInterceptor 的攔截器。
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new RefererInterceptor());
}
}使用Nginx
可以使用Nginx通過(guò)配置實(shí)現(xiàn)非法盜鏈防護(hù),主要使用valid_referers 參數(shù)
valid_referers:指定允許訪問(wèn)該網(wǎng)站資源的有效來(lái)源,可以設(shè)置為多個(gè)值,用空格分隔,如valid_referers example.com *.example.com; 表示只允許來(lái)自example.com或者其子域名的訪問(wèn)。
如果請(qǐng)求的 Referer 頭不存在或者不在 valid_referers 中,則會(huì)將 $invalid_referer 設(shè)置為 1,進(jìn)而返回 HTTP 狀態(tài)碼 403
具體實(shí)現(xiàn)如下:
location ~ .*\.(jpg|jpeg|JPG|png|gif|icon)$ {
valid_referers blocked example.com *.example.com;
if ($invalid_referer) {
return 403;
}
}限制訪問(wèn)權(quán)限
在資源服務(wù)器和客戶(hù)端上分別進(jìn)行配置,實(shí)現(xiàn)認(rèn)證和授權(quán)機(jī)制。服務(wù)端可以使用JavaEE 中的Servlet、Filter 或Spring Security等框架來(lái)實(shí)現(xiàn)認(rèn)證和授權(quán)??蛻?hù)端則需要在請(qǐng)求中攜帶身份認(rèn)證憑證,如token、session id等
客戶(hù)端發(fā)送請(qǐng)求時(shí)攜帶身份認(rèn)證憑證:
# 用戶(hù)身份認(rèn)證憑證
String token = "123456789";
HttpURLConnection conn = (HttpURLConnection) new URL("http://www.test.com/img.jpg").openConnection();
// 在請(qǐng)求頭中添加 Authorization 字段攜帶憑證
conn.setRequestProperty("Authorization", "Bearer "+token); 服務(wù)端進(jìn)行認(rèn)證:
// 獲取請(qǐng)求頭中的認(rèn)證字段
String authHeader = request.getHeader("Authorization");
if(authHeader != null && authHeader.startsWith("Bearer ")){
// 提取認(rèn)證憑證
String token = authHeader.substring(7);
// TODO 對(duì)憑證進(jìn)行校驗(yàn)或者查詢(xún)授權(quán)信息
} else{
}動(dòng)態(tài)生成鏈接
在服務(wù)端對(duì)每個(gè)請(qǐng)求生成唯一的一次性鏈接,在處理請(qǐng)求時(shí)驗(yàn)證該鏈接是否合法??梢允褂肑ava中的UUID類(lèi)來(lái)生成隨機(jī)字符串作為鏈接的參數(shù)。這種方法能夠有效保護(hù)資源的安全,但對(duì)服務(wù)器壓力較大。
生成唯一帶簽名的鏈接
private static final String KEY = "YOUR_SECRET_KEY"; // 設(shè)置秘鑰
?? ?/**
? ? ?* 傳入原始鏈接作為參數(shù),即可生成帶有時(shí)間戳、隨機(jī)數(shù)和簽名的新鏈接
? ? ?* @param url 訪問(wèn)URL
? ? ?*/
? ? public static String generateLink(String url) throws NoSuchAlgorithmException {
? ? ? ? // 當(dāng)前時(shí)間戳
? ? ? ? String timestamp = System.currentTimeMillis() + "";
? ? ? ? // 隨機(jī)數(shù)
? ? ? ? String nonce = Long.toString(Math.round(Math.random() * 10000));
? ? ? ? // 簽名內(nèi)容
? ? ? ? String rawSignature = url + timestamp + nonce + KEY;
? ? ? ? // 使用 SHA-256 算法生成簽名
? ? ? ? MessageDigest md = MessageDigest.getInstance("SHA-256");
? ? ? ? byte[] signature = md.digest(rawSignature.getBytes());
? ? ? ? // Base64 編碼
? ? ? ? String encodedSignature = Base64.getEncoder().encodeToString(signature);
? ? ? ? // 生成鏈接
? ? ? ? String link = url + "?timestamp=" + timestamp + "&nonce=" + nonce + "&signature=" + encodedSignature;
? ? ? ? return link;
? ? }校驗(yàn)鏈接是否合法
校驗(yàn)步驟:
從鏈接中取出 timestamp、nonce 和 signature 三個(gè)參數(shù)
使用與鏈接生成時(shí)相同的秘鑰、算法(SHA-256)和編碼方式(Base64)對(duì)原始內(nèi)容進(jìn)行簽名,獲得新的簽名值
比較從鏈接中獲得的簽名值和新的簽名值是否一致
如果簽名值一致,并且 timestamp 和 nonce 參數(shù)符合要求(如沒(méi)有重復(fù)),則認(rèn)為該鏈接是合法的
private static final String KEY = "YOUR_SECRET_KEY"; // 設(shè)置秘鑰
? ? /**
? ? ?* 如果返回 true 則說(shuō)明鏈接合法,可以繼續(xù)訪問(wèn)
? ? ?* 如果返回 false,則說(shuō)明鏈接不合法,需要返回錯(cuò)誤信息或者重定向到其他頁(yè)面
? ? ?* @param url 訪問(wèn)URL
? ? ?* @param timestamp 時(shí)間戳
? ? ?* @param nonce 隨機(jī)數(shù)
? ? ?* @param signature 簽名
? ? ?*/
? ? public static boolean isValidLink(String url, String timestamp, String nonce, String signature) throws NoSuchAlgorithmException {
? ? ? ? // 簽名內(nèi)容
? ? ? ? String rawSignature = url + timestamp + nonce + KEY;
? ? ? ? // 使用 SHA-256 算法生成簽名
? ? ? ? MessageDigest md = MessageDigest.getInstance("SHA-256");
? ? ? ? byte[] newSignature = md.digest(rawSignature.getBytes());
? ? ? ? // Base64 編碼
? ? ? ? String encodedSignature = Base64.getEncoder().encodeToString(newSignature);
? ? ? ? // 校驗(yàn)簽名值和其他參數(shù)
? ? ? ? return encodedSignature.equals(signature);
? ? }測(cè)試
?public static void main(String[] args) throws Exception {
? ? ? ? String link = DynamicLink.generateLink("/test");
? ? ? ? // link = /test?timestamp=1683100020877&nonce=9081&signature=vD2S/Ki7a/SLhRj19mcqDmylKKO3OTKTtpA/CUZJMg0=
? ? ? ? System.out.println("link = " + link);
? ? ? ? boolean validLink = DynamicLink.isValidLink("/test", "1683100020877", "9081", "vD2S/Ki7a/SLhRj19mcqDmylKKO3OTKTtpA/CUZJMg0=");
? ? ? ? System.out.println("validLink = " + validLink);
? ? }link = /test?timestamp=1683100020877&nonce=9081&signature=vD2S/Ki7a/SLhRj19mcqDmylKKO3OTKTtpA/CUZJMg0= validLink = true
添加水印
在資源服務(wù)器上進(jìn)行配置,在服務(wù)端對(duì)資源進(jìn)行加水印處理,并在客戶(hù)端顯示處理后的結(jié)果。Java可以使用Graphics2D工具類(lèi)來(lái)添加水印。
參考:Java實(shí)現(xiàn)添加文字水印、圖片水印功能
CDN防盜鏈
利用CDN服務(wù)商的防盜鏈功能,限制只有經(jīng)過(guò)授權(quán)的域名才能訪問(wèn)資源。
訪問(wèn)頻率限制
通過(guò)IP地址或用戶(hù)會(huì)話ID等方式限制同一客戶(hù)端在一段時(shí)間內(nèi)對(duì)資源的訪問(wèn)頻率,防止非法爬取和盜鏈。
到此這篇關(guān)于Java防止非法盜鏈的幾種解決方案的文章就介紹到這了,更多相關(guān)Java防止非法盜鏈內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中this和super的區(qū)別及this能否調(diào)用到父類(lèi)使用
這篇文章主要介紹了Java中this和super的區(qū)別及this能否調(diào)用到父類(lèi)使用,this和super都是Java中常見(jiàn)的關(guān)鍵字,下文關(guān)于兩者區(qū)別介紹,需要的小伙伴可以參考一下2022-05-05
ExpressionUtil工具類(lèi)的應(yīng)用實(shí)例
這篇文章主要給大家介紹了關(guān)于ExpressionUtil工具類(lèi)的應(yīng)用實(shí)例,常用的工具類(lèi)有很多,這是其中一個(gè),了解基本的API可以幫助我們更好的開(kāi)發(fā),文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-04-04
解決@FeignClient注入service失敗問(wèn)題
這篇文章主要介紹了解決@FeignClient注入service失敗問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
es(elasticsearch)整合SpringCloud(SpringBoot)搭建教程詳解
這篇文章主要介紹了es(elasticsearch)整合SpringCloud(SpringBoot)搭建教程,本文通過(guò)實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
Java利用jenkins做項(xiàng)目的自動(dòng)化部署
這篇文章主要介紹了Java利用jenkins做項(xiàng)目的自動(dòng)化部署,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06
mybatisplus的坑?insert標(biāo)簽insert?into?select無(wú)參數(shù)問(wèn)題的解決
這篇文章主要介紹了mybatisplus的坑?insert標(biāo)簽insert?into?select無(wú)參數(shù)問(wèn)題的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12

