图片防盗链(Image Hotlinking Prevention)是一种常见的安全措施,旨在防止其他网站未经许可直接引用你的图片资源。这不仅能保护你的服务器带宽,避免不必要的资源消耗,还可以保证你的网站内容的版权和完整性。

在这篇文章中,我们将详细分析前端和后端如何配合实现图片防盗链技术,特别是在 Spring Boot 环境下的解决方案。


1. 图片防盗链的原理分析

1.1 什么是图片防盗链?

盗链(Hotlinking)指的是其他网站通过直接引用你网站的资源(如图片、视频、样式表等),而不是下载这些资源到自己的服务器,从而消耗你网站的带宽和资源。这种做法不仅影响服务器性能,还可能导致版权问题和内容篡改的风险。

图片防盗链技术,就是通过一系列手段来防止其他网站直接引用你的图片。

1.2 防盗链的基本原理

防盗链的核心思想是通过验证请求的来源(如 HTTP 请求头中的 Referer 字段)来确保请求来自合法的来源网站。如果请求来自非法网站(即请求头中的 Referer 不是预期中的域名),则拒绝该请求,返回错误或占位图。

常见的防盗链方法包括:

  • Referer 校验:验证请求的 Referer 字段,只有合法来源才能访问资源。
  • Token 校验:生成有效的 token,并将其附加在 URL 中进行校验。
  • 签名校验:对 URL 进行加密签名,验证请求是否合法。

2. 前端解决方案:Referer 校验

虽然防盗链的核心功能通常由后端实现,前端也可以通过某些方式配合防盗链。

2.1 使用 Referer 校验

当一个图片被加载时,浏览器会自动发送一个 HTTP 请求,其中包括 Referer 字段,该字段指示了图片请求的来源页面。通过后端检查该字段,我们可以判断请求是否来自允许的域名。

例如,在前端加载图片时,如果我们希望限制图片的引用来源为自己的站点,后端就可以检查 Referer 是否为本站域名。

<!-- 前端页面引用图片 -->
<img src="https://yourdomain.com/images/pic.jpg" alt="image">

当用户访问该页面时,浏览器会发送如下请求:

GET /images/pic.jpg HTTP/1.1
Host: yourdomain.com
Referer: https://alloweddomain.com

在这种情况下,服务器可以根据 Referer 字段的值进行判断,若请求来源不合法,则拒绝返回图片。


3. 后端解决方案:Spring Boot 实现图片防盗链

Spring Boot 中,我们可以通过过滤器或拦截器来检查 HTTP 请求中的 Referer 字段,并进行防盗链操作。下面是一个基于 Spring Boot 的实现方案。

3.1 使用过滤器拦截图片请求

Spring Boot 提供了强大的过滤器机制,允许我们在请求到达控制器之前对请求进行处理。我们可以使用一个过滤器来拦截图片请求,检查 Referer 字段是否来自合法的来源。

3.1.1 定义防盗链过滤器
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(urlPatterns = "/images/*")  // 只拦截图片资源请求
public class ImageAntiHotlinkingFilter implements Filter {

    private static final String ALLOWED_REFERER = "https://www.yourdomain.com";  // 允许的来源域名
    private static final String DEFAULT_IMAGE_URL = "/images/default.jpg";  // 防盗链时显示的默认图片

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化操作
    }

    @Override
    public void doFilter(javax.servlet.ServletRequest request, javax.servlet.ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        String referer = httpRequest.getHeader("Referer");

        // 判断请求的 Referer 是否合法
        if (referer == null || !referer.startsWith(ALLOWED_REFERER)) {
            // 非法来源,重定向到默认图片
            httpResponse.sendRedirect(DEFAULT_IMAGE_URL);
            return;
        }

        // 合法请求,继续处理
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // 销毁操作
    }
}

3.1.2 注册过滤器

然后,在 Spring Boot 中通过 @Configuration 注解将该过滤器注册到 Spring 容器中。

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class WebConfig {

    @Bean
    public FilterRegistrationBean<ImageAntiHotlinkingFilter> imageFilter() {
        FilterRegistrationBean<ImageAntiHotlinkingFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new ImageAntiHotlinkingFilter());
        registrationBean.addUrlPatterns("/images/*");  // 只拦截图片路径
        return registrationBean;
    }
}

3.2 使用 Spring Security 防盗链(更细致控制)

如果你已经使用 Spring Security 进行访问控制,你可以将防盗链的逻辑与 Spring Security 配置结合起来,进行更精细的安全控制。

例如,你可以通过 HttpSecurity 配置来实现对特定资源的访问控制:

import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
            .antMatchers("/images/**").permitAll()  // 图片路径允许匿名访问
            .anyRequest().authenticated()
            .and()
            .addFilterBefore(new ImageAntiHotlinkingFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}

这种方法可以结合 Spring Security 实现更细致的权限管理。

3.3 防盗链的其他高级实现

如果你希望防盗链更加安全,可以考虑:

  • Token 防盗链:在图片 URL 中嵌入临时有效的 token,并在后端进行验证。
  • 时间戳防盗链:通过 URL 中添加时间戳,只有在有效时间段内才允许访问。
  • 签名防盗链:对 URL 进行签名,确保 URL 的合法性。

4. 总结

防盗链的实现方式有很多种,主要通过验证请求来源来防止外部网站恶意使用你的资源。在前端,我们可以通过配置图片的引用方式、使用 Referer 校验来限制资源访问。而在后端,Spring Boot 提供了过滤器和 Spring Security 的配置,使得我们可以方便地实现防盗链功能。

通过这篇文章,我们详细分析了如何实现图片防盗链技术,以及如何在 Spring Boot 环境下结合过滤器和 Spring Security 完成该功能的实现。