1、什么是CSRF漏洞?

CSRF(跨站请求伪造)攻击确实可被用于篡改账户信息、执行转账操作或修改敏感配置,其核心原理是攻击者诱导用户浏览器在用户不知情的情况下,向目标网站发送携带用户身份验证信息(如Cookie)的恶意请求。为有效防范此类攻击,可从技术防护、用户操作规范、系统架构优化三个层面进行针对性修改与加固。

2、解决措施:验证HTTP Referer字段

  • 说明:该措施是众多解决措施一种,我的项目适用,本文仅作记录。
  • 原理:检查请求的Referer头,确保请求来自合法来源。
  • 实施方式
    • 服务端验证Referer头是否以目标网站域名开头,若来自其他域名则拒绝请求

3、项目配置措施

1)寻找安全配置类,继承自 WebSecurityConfigurerAdapter 的类

2)在 configure(HttpSecurity http) 方法中添加referer校验逻辑:

.addFilterBefore(new RefererValidationFilter(), UsernamePasswordAuthenticationFilter.class)

【说明】

UsernamePasswordAuthenticationFilter导入的包:import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .csrf().disable()
                .addFilterBefore(new RefererValidationFilter(), UsernamePasswordAuthenticationFilter.class);
    }
RefererValidationFilter类如下:
package ..............;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

@Slf4j
public class RefererValidationFilter extends OncePerRequestFilter {

    // 允许的域名列表
    private List<String> allowedDomains = Arrays.asList(
        "localhost",
        "127.0.0.1"
    );

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {

        String referer = request.getHeader("Referer");
        log.info("校验referer: {}", referer);

        // 对于敏感请求方法进行referer校验
        if (isSensitiveMethod(request.getMethod()) && !isValidReferer(referer)) {
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            response.getWriter().write("Invalid referer");
            return;
        }

        filterChain.doFilter(request, response);
    }

    private boolean isSensitiveMethod(String method) {
        // 对POST、PUT、DELETE等敏感操作进行校验
        return "POST".equals(method) || "PUT".equals(method) || "GET".equals(method) ||
               "DELETE".equals(method) || "PATCH".equals(method);
    }

    private boolean isValidReferer(String referer) {
        if (referer == null || referer.isEmpty()) {
            return false;
        }

        try {
            String refererHost = new java.net.URL(referer).getHost();
            return allowedDomains.stream().anyMatch(domain ->
                refererHost.equals(domain) || refererHost.endsWith("." + domain)
            );
        } catch (Exception e) {
            return false;
        }
    }
}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐