Java防止非法盗链的几种解决方案
作者:CodeDevMaster
非法盗链概述
非法盗链指的是在未获得授权的情况下,将别人的资源(如图片、视频等)直接链接到自己的网站上,从而消耗他人的带宽和流量,并影响原始资源的安全性。
HTTP Referer请求头验证
通过检查HTTP头部中的Referer字段,判断请求来源是否合法。只允许来自特定域名或IP地址的请求才能访问资源。这种方法较容易实施,不过存在一定的伪造风险。
Spring MVC项目
创建RefererFilter类实现Filter接口并重写3个方法,实现过滤逻辑。
在处理请求时判断请求头中的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项目
创建一个拦截器来对 HTTP Referer 请求头进行验证
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通过配置实现非法盗链防护,主要使用valid_referers 参数
valid_referers:指定允许访问该网站资源的有效来源,可以设置为多个值,用空格分隔,如valid_referers example.com *.example.com; 表示只允许来自example.com或者其子域名的访问。
如果请求的 Referer 头不存在或者不在 valid_referers 中,则会将 $invalid_referer 设置为 1,进而返回 HTTP 状态码 403
具体实现如下:
location ~ .*\.(jpg|jpeg|JPG|png|gif|icon)$ { valid_referers blocked example.com *.example.com; if ($invalid_referer) { return 403; } }
限制访问权限
在资源服务器和客户端上分别进行配置,实现认证和授权机制。服务端可以使用JavaEE 中的Servlet、Filter 或Spring Security等框架来实现认证和授权。客户端则需要在请求中携带身份认证凭证,如token、session id等
客户端发送请求时携带身份认证凭证:
# 用户身份认证凭证 String token = "123456789"; HttpURLConnection conn = (HttpURLConnection) new URL("http://www.test.com/img.jpg").openConnection(); // 在请求头中添加 Authorization 字段携带凭证 conn.setRequestProperty("Authorization", "Bearer "+token);
服务端进行认证:
// 获取请求头中的认证字段 String authHeader = request.getHeader("Authorization"); if(authHeader != null && authHeader.startsWith("Bearer ")){ // 提取认证凭证 String token = authHeader.substring(7); // TODO 对凭证进行校验或者查询授权信息 } else{ }
动态生成链接
在服务端对每个请求生成唯一的一次性链接,在处理请求时验证该链接是否合法。可以使用Java中的UUID类来生成随机字符串作为链接的参数。这种方法能够有效保护资源的安全,但对服务器压力较大。
生成唯一带签名的链接
private static final String KEY = "YOUR_SECRET_KEY"; // 设置秘钥 /** * 传入原始链接作为参数,即可生成带有时间戳、随机数和签名的新链接 * @param url 访问URL */ public static String generateLink(String url) throws NoSuchAlgorithmException { // 当前时间戳 String timestamp = System.currentTimeMillis() + ""; // 随机数 String nonce = Long.toString(Math.round(Math.random() * 10000)); // 签名内容 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 三个参数
使用与链接生成时相同的秘钥、算法(SHA-256)和编码方式(Base64)对原始内容进行签名,获得新的签名值
比较从链接中获得的签名值和新的签名值是否一致
如果签名值一致,并且 timestamp 和 nonce 参数符合要求(如没有重复),则认为该链接是合法的
private static final String KEY = "YOUR_SECRET_KEY"; // 设置秘钥 /** * 如果返回 true 则说明链接合法,可以继续访问 * 如果返回 false,则说明链接不合法,需要返回错误信息或者重定向到其他页面 * @param url 访问URL * @param timestamp 时间戳 * @param nonce 随机数 * @param signature 签名 */ public static boolean isValidLink(String url, String timestamp, String nonce, String signature) throws NoSuchAlgorithmException { // 签名内容 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); // 校验签名值和其他参数 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
添加水印
在资源服务器上进行配置,在服务端对资源进行加水印处理,并在客户端显示处理后的结果。Java可以使用Graphics2D工具类来添加水印。
CDN防盗链
利用CDN服务商的防盗链功能,限制只有经过授权的域名才能访问资源。
访问频率限制
通过IP地址或用户会话ID等方式限制同一客户端在一段时间内对资源的访问频率,防止非法爬取和盗链。
到此这篇关于Java防止非法盗链的几种解决方案的文章就介绍到这了,更多相关Java防止非法盗链内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!