浅析Spring Security如何防止CSRF攻击

 更新时间:2025年07月04日 10:07:24   作者:Java皇帝  
CSRF(Cross-Site Request Forgery)攻击,即跨站请求伪造攻击,本文主要为大家整理了Spring Security防止CSRF攻击的相关方法,大家可以根据需要进行选择

一、CSRF 攻击简介

CSRF(Cross-Site Request Forgery)攻击,即跨站请求伪造攻击,是一种利用用户已登录的身份,在用户不知情的情况下,强制其执行非预期操作的攻击方式。攻击者通常会通过伪造的请求,诱使用户在已登录的应用程序中执行恶意操作,例如转账、修改个人信息等。

二、Spring Security 防止 CSRF 攻击的机制

1. 默认启用 CSRF 保护

从 Spring Security 4.0 开始,默认情况下会启用 CSRF 保护。这意味着对于 PATCH、POST、PUT 和 DELETE 方法的请求,Spring Security 会自动进行 CSRF 验证。

2. CSRF 令牌的生成与验证

Spring Security 通过生成唯一的 CSRF 令牌(Token)来防止 CSRF 攻击。具体流程如下:

  • 生成 CSRF 令牌:服务器在处理请求时,会生成一个唯一的 CSRF 令牌,并将其存储在用户的会话(HttpSession)或 Cookie 中。
  • 客户端提交 CSRF 令牌:客户端在提交表单或发送 AJAX 请求时,需要将 CSRF 令牌包含在请求中。通常,这个令牌会作为表单的一个隐藏字段或请求头的一部分发送。
  • 服务器验证 CSRF 令牌:服务器在接收到请求后,会从请求中提取 CSRF 令牌,并与存储在会话或 Cookie 中的令牌进行比较。如果两者一致,则认为请求是合法的;如果不一致,则认为是 CSRF 攻击,服务器会拒绝该请求。

3. 配置与自定义

开启或关闭 CSRF 保护:可以通过配置来开启或关闭 CSRF 保护。例如,在基于 Java 配置的项目中,可以通过以下代码关闭 CSRF 保护:

http.csrf().disable();

或者在基于 XML 配置的项目中,使用以下代码:

<security:csrf disabled="true"/>

自定义 CSRF 令牌存储方式:Spring Security 提供了 CsrfTokenRepository 接口,开发者可以实现该接口来自定义 CSRF 令牌的存储和获取方式。默认实现是 HttpSessionCsrfTokenRepository,它将 CSRF 令牌存储在 HttpSession 中。

4. 在请求中包含 CSRF 令牌

表单提交:在 HTML 表单中,可以通过 Thymeleaf 等模板引擎自动包含 CSRF 令牌。例如:

<form action="/submit" method="POST">
    <input type="hidden" name="_csrf" value="${_csrf.token}" />
    <button type="submit">Submit</button>
</form>

AJAX 请求:在使用 AJAX 提交请求时,需要手动将 CSRF 令牌添加到请求头中。例如,使用 jQuery 时可以这样操作:

$.ajax({
    url: '/submit',
    type: 'POST',
    headers: {
        'X-CSRF-TOKEN': $('meta[name="_csrf"]').attr('content')
    },
    data: {
        // Your data here
    },
    success: function(response) {
        console.log(response);
    },
    error: function(xhr, status, error) {
        console.error('Error:', error);
    }
});

在 HTML 中,需要包含 CSRF 令牌的 meta 标签:

<meta name="_csrf" content="${_csrf.token}" />

三、最佳实践

  • 始终启用 CSRF 保护:除非有充分的理由,否则应始终启用 CSRF 保护,以确保应用程序的安全性。
  • 使用 HTTPS:通过使用 HTTPS,可以防止攻击者拦截和篡改请求,从而提高应用程序的安全性。
  • 限制 CSRF 令牌的作用域:可以配置 CSRF 令牌仅对特定的端点有效,从而减少潜在的安全风险。
  • 定期更新依赖:及时更新 Spring Security 和其他相关依赖,以修复已知的安全漏洞。

四、方法补充

Spring Security 防止 CSRF 攻击

使用 security 是 3.3.2 版本

1、 启用 CSRF ,security 自带功能

@Bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        // 禁用默认的登录和退出
        httpSecurity.formLogin(AbstractHttpConfigurer::disable);
        httpSecurity.logout(AbstractHttpConfigurer::disable);
        //开启 CSRF
        httpSecurity.csrf(csrf -> csrf
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()));
        httpSecurity.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
        // 配置拦截规则
        httpSecurity.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
            // 放行白名单
            .requestMatchers(CollUtil.isEmpty(ignoreWhiteProperties.getWhites()) ? new String[0] :
                ignoreWhiteProperties.getWhites().toArray(new String[0])).permitAll()
            // 需要鉴权认证
            .anyRequest().authenticated());

        // 添加过滤器
        httpSecurity.addFilterBefore(authTokenFilter(), UsernamePasswordAuthenticationFilter.class);

        // 异常时认证处理流程
        httpSecurity.exceptionHandling(
            exceptionHandlingConfigurer -> exceptionHandlingConfigurer.authenticationEntryPoint(
                authenticationEntryPoint()).accessDeniedHandler(accessDeniedHandler()));
        return httpSecurity.build();
    }

2、 spring gateway  中添加过滤器先进行添加36位 空字符,再进行 base64 编码,重新写入请求头中

package com.changan.gateway.filter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * CSRF 在头信息中额外生成36个空字符,使其校验通过
 */
@Component
public class CsrfGlobalFilter implements GlobalFilter {

    private final StringBuffer preHead = new StringBuffer();

    public CsrfGlobalFilter(){
        // 生成36位随机数
        preHead.append("\u0000".repeat(36));
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取前端传递的 X-Xsrf-Token 头信息
        String headerValue = exchange.getRequest().getHeaders().getFirst("X-Xsrf-Token");
        //在 X-Xsrf-Token 头信息之前添加 36 位空字符
        headerValue = preHead + headerValue;
        //base64 加密
        String encodedValue = Base64.getEncoder().encodeToString(headerValue.getBytes(StandardCharsets.UTF_8));

        exchange.getRequest().mutate()
                .header("X-Xsrf-Token", encodedValue)
                .build();

        return chain.filter(exchange);
    }

}

总结:

Security 自带 CSRF 功能,他会在第一次 POST 请求后会在 cookie 中存储一个 csrf_token 值,前端有的框架会自动识别,下次请求会自动携带上,就可以防止 CSRF 攻击

注意:

按常理是这样的,可是 3.3.2 版本跟进源码发现,需要有一个 36 位 前缀随机数,但是后续需要异或运算= csrf_token 本身才放行。这里应该是要通过计算得出。

上述为了能实现功能,暂时直接用 “空字符” 也能成功

五、总结

Spring Security 提供了强大的 CSRF 防护机制,通过生成和验证 CSRF 令牌,有效防止了 CSRF 攻击。开发者可以通过配置和自定义来满足不同的安全需求,同时遵循最佳实践,确保应用程序的安全性。

到此这篇关于浅析Spring Security如何防止CSRF攻击的文章就介绍到这了,更多相关Spring Security防CSRF攻击内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 教你如何精准统计出你的接口

    教你如何精准统计出你的接口"QPS"

    今天小编就为大家分享一篇关于QPS的精准计算方法,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2021-08-08
  • Java日常练习题,每天进步一点点(60)

    Java日常练习题,每天进步一点点(60)

    下面小编就为大家带来一篇Java基础的几道练习题(分享)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望可以帮到你
    2021-08-08
  • 用Java实现简单画板功能

    用Java实现简单画板功能

    这篇文章主要为大家详细介绍了用Java实现简单画板功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • 基于java构造方法Vevtor添加元素源码分析

    基于java构造方法Vevtor添加元素源码分析

    这篇文章主要介绍了基于java构造方法中对Vevtor添加元素的源码分析,有需要的朋友可以借鉴参考下,希望可以对大家有所帮助,祝大家早日升职加薪
    2021-09-09
  • java阿拉伯数字转中文数字

    java阿拉伯数字转中文数字

    这篇文章主要为大家详细介绍了java实现阿拉伯数字转换为中文数字,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-04-04
  • Java web xml文件读取解析方式

    Java web xml文件读取解析方式

    这篇文章主要介绍了Java web xml文件读取解析方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • 带你用Java方法轻松实现树的同构

    带你用Java方法轻松实现树的同构

    给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树
    2021-06-06
  • Spring Boot实现JWT token自动续期的实现

    Spring Boot实现JWT token自动续期的实现

    本文主要介绍了Spring Boot实现JWT token自动续期,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • Java枚举_动力节点Java学院整理

    Java枚举_动力节点Java学院整理

    enum 的全称为 enumeration, 是 JDK 5 中引入的新特性,存放在 java.lang 包中。这篇文章给大家介绍Java枚举相关知识,需要的的朋友参考下
    2017-04-04
  • JAVA用for循环打印空心菱形

    JAVA用for循环打印空心菱形

    大家好,本篇文章主要讲的是JAVA用for循环打印空心菱形,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01

最新评论