Java防止非法盜鏈的幾種解決方案
非法盜鏈概述
非法盜鏈指的是在未獲得授權(quán)的情況下,將別人的資源(如圖片、視頻等)直接鏈接到自己的網(wǎng)站上,從而消耗他人的帶寬和流量,并影響原始資源的安全性。
HTTP Referer請求頭驗證
通過檢查HTTP頭部中的Referer字段,判斷請求來源是否合法。只允許來自特定域名或IP地址的請求才能訪問資源。這種方法較容易實施,不過存在一定的偽造風(fēng)險。
Spring MVC項目
創(chuàng)建RefererFilter類實現(xiàn)Filter接口并重寫3個方法,實現(xiàn)過濾邏輯。
在處理請求時判斷請求頭中的Referer字段,然后通過字符串比較或正則匹配可以判斷請求來源是否合法,如果不合法可以返回錯誤信息或重定向到其他頁面。
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("攔截請求..."); ? ? ? ? HttpServletRequest req = (HttpServletRequest) request; ? ? ? ? HttpServletResponse res = (HttpServletResponse) response; ? ? ? ? //每次請求來源 ? ? ? ? String referer = req.getHeader("referer"); ? ? ? ? //獲取請求地址 ? ? ? ? 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("銷毀請求..."); ? ? } }
web.xml配置過濾器
<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項目
創(chuàng)建一個攔截器來對 HTTP Referer 請求頭進(jì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"); ? ? ? ? // 如果請求頭中的 Referer 不是允許的域名,則返回 403 錯誤 ? ? ? ? if (referer == null || !referer.startsWith(ALLOWED_REFERER)) { ? ? ? ? ? ? response.sendError(HttpServletResponse.SC_FORBIDDEN); ? ? ? ? ? ? return false; ? ? ? ? } ? ? ? ? // 否則放行 ? ? ? ? return true; ? ? } }
通過 WebMvcConfigurer 接口和 addInterceptors 方法注冊了名為 RefererInterceptor 的攔截器。
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RefererInterceptor()); } }
使用Nginx
可以使用Nginx通過配置實現(xiàn)非法盜鏈防護(hù),主要使用valid_referers 參數(shù)
valid_referers:指定允許訪問該網(wǎng)站資源的有效來源,可以設(shè)置為多個值,用空格分隔,如valid_referers example.com *.example.com; 表示只允許來自example.com或者其子域名的訪問。
如果請求的 Referer 頭不存在或者不在 valid_referers 中,則會將 $invalid_referer 設(shè)置為 1,進(jìn)而返回 HTTP 狀態(tài)碼 403
具體實現(xiàn)如下:
location ~ .*\.(jpg|jpeg|JPG|png|gif|icon)$ { valid_referers blocked example.com *.example.com; if ($invalid_referer) { return 403; } }
限制訪問權(quán)限
在資源服務(wù)器和客戶端上分別進(jìn)行配置,實現(xiàn)認(rèn)證和授權(quán)機(jī)制。服務(wù)端可以使用JavaEE 中的Servlet、Filter 或Spring Security等框架來實現(xiàn)認(rèn)證和授權(quán)??蛻舳藙t需要在請求中攜帶身份認(rèn)證憑證,如token、session id等
客戶端發(fā)送請求時攜帶身份認(rèn)證憑證:
# 用戶身份認(rèn)證憑證 String token = "123456789"; HttpURLConnection conn = (HttpURLConnection) new URL("http://www.test.com/img.jpg").openConnection(); // 在請求頭中添加 Authorization 字段攜帶憑證 conn.setRequestProperty("Authorization", "Bearer "+token);
服務(wù)端進(jìn)行認(rèn)證:
// 獲取請求頭中的認(rèn)證字段 String authHeader = request.getHeader("Authorization"); if(authHeader != null && authHeader.startsWith("Bearer ")){ // 提取認(rèn)證憑證 String token = authHeader.substring(7); // TODO 對憑證進(jìn)行校驗或者查詢授權(quán)信息 } else{ }
動態(tài)生成鏈接
在服務(wù)端對每個請求生成唯一的一次性鏈接,在處理請求時驗證該鏈接是否合法??梢允褂肑ava中的UUID類來生成隨機(jī)字符串作為鏈接的參數(shù)。這種方法能夠有效保護(hù)資源的安全,但對服務(wù)器壓力較大。
生成唯一帶簽名的鏈接
private static final String KEY = "YOUR_SECRET_KEY"; // 設(shè)置秘鑰 ?? ?/** ? ? ?* 傳入原始鏈接作為參數(shù),即可生成帶有時間戳、隨機(jī)數(shù)和簽名的新鏈接 ? ? ?* @param url 訪問URL ? ? ?*/ ? ? public static String generateLink(String url) throws NoSuchAlgorithmException { ? ? ? ? // 當(dāng)前時間戳 ? ? ? ? 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; ? ? }
校驗鏈接是否合法
校驗步驟:
從鏈接中取出 timestamp、nonce 和 signature 三個參數(shù)
使用與鏈接生成時相同的秘鑰、算法(SHA-256)和編碼方式(Base64)對原始內(nèi)容進(jìn)行簽名,獲得新的簽名值
比較從鏈接中獲得的簽名值和新的簽名值是否一致
如果簽名值一致,并且 timestamp 和 nonce 參數(shù)符合要求(如沒有重復(fù)),則認(rèn)為該鏈接是合法的
private static final String KEY = "YOUR_SECRET_KEY"; // 設(shè)置秘鑰 ? ? /** ? ? ?* 如果返回 true 則說明鏈接合法,可以繼續(xù)訪問 ? ? ?* 如果返回 false,則說明鏈接不合法,需要返回錯誤信息或者重定向到其他頁面 ? ? ?* @param url 訪問URL ? ? ?* @param timestamp 時間戳 ? ? ?* @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); ? ? ? ? // 校驗簽名值和其他參數(shù) ? ? ? ? return encodedSignature.equals(signature); ? ? }
測試
?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ù)端對資源進(jìn)行加水印處理,并在客戶端顯示處理后的結(jié)果。Java可以使用Graphics2D工具類來添加水印。
CDN防盜鏈
利用CDN服務(wù)商的防盜鏈功能,限制只有經(jīng)過授權(quán)的域名才能訪問資源。
訪問頻率限制
通過IP地址或用戶會話ID等方式限制同一客戶端在一段時間內(nèi)對資源的訪問頻率,防止非法爬取和盜鏈。
到此這篇關(guān)于Java防止非法盜鏈的幾種解決方案的文章就介紹到這了,更多相關(guān)Java防止非法盜鏈內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
查找native方法的本地實現(xiàn)函數(shù)native_function詳解
JDK開放給用戶的源碼中隨處可見Native方法,被Native關(guān)鍵字聲明的方法說明該方法不是以Java語言實現(xiàn)的,而是以本地語言實現(xiàn)的,Java可以直接拿來用。這里介紹下查找native方法的本地實現(xiàn)函數(shù)native_function,感興趣的朋友跟隨小編一起看看吧2021-12-12jackson 如何將實體轉(zhuǎn)json json字符串轉(zhuǎn)實體
這篇文章主要介紹了jackson 實現(xiàn)將實體轉(zhuǎn)json json字符串轉(zhuǎn)實體,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10Java編程redisson實現(xiàn)分布式鎖代碼示例
這篇文章主要介紹了Java編程redisson實現(xiàn)分布式鎖代碼示例,小編覺得還是比較不錯的,這里給大家分享下,供需要的朋友參考。2017-10-10SpringBoot利用注解來實現(xiàn)Redis分布式鎖
有些業(yè)務(wù)請求,屬于耗時操作,需要加鎖,防止后續(xù)的并發(fā)操作,同時對數(shù)據(jù)庫的數(shù)據(jù)進(jìn)行操作,需要避免對之前的業(yè)務(wù)造成影響。本文將利用注解來實現(xiàn)Redis分布式鎖,需要的可以參考一下2022-09-09詳解IntelliJ IDEA 中如何配置多個jdk版本即(1.7和1.8兩個jdk都可用)
這篇文章主要介紹了詳解IntelliJ IDEA 中如何配置多個jdk版本即(1.7和1.8兩個jdk都可用),非常具有實用價值,需要的朋友可以參考下2017-11-11Springboot啟動擴(kuò)展點超詳細(xì)教程小結(jié)
這篇文章主要介紹了Springboot啟動擴(kuò)展點超詳細(xì)教程小結(jié),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07使用Post方法模擬登陸爬取網(wǎng)頁的實現(xiàn)方法
下面小編就為大家?guī)硪黄褂肞ost方法模擬登陸爬取網(wǎng)頁的實現(xiàn)方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-03-03