SpringSecurity跨域请求伪造(CSRF)的防护实现

为了防止SpringSecurity跨域请求伪造(CSRF)攻击,需要采取一些措施来进行防护实现。下面是实现CSRF防护的步骤:

1.同源检查

这是最常见的CSRF防护方法,包括验证请求的源(Origin),或者Referrer)与app地址是否相同,建议把这个配置在Spring Security中,只需在SpringSecurity的配置类中添加如下代码:

http.csrf().requireCsrfProtectionMatcher(new CSRFRequireSamesiteMatcher());

此处使用CSRFRequireSamesiteMatcher来进行same-site检测,这可以防止第三方站点进行CSRF攻击。如果源(Origin),或者Referrer)与app地址不同,spring security将拒绝该请求。

2.Token验证

在服务器端为每个用户生成一个随机的token,然后将其存储在session中,并在每个表单提交中包含一个隐藏的字段,包含Token。客户端使用该token作为表单参数,服务端进行校验。SpringSecurity已经集成了处理该场景的组件CsrfTokenRepository,你可以直接注入此组件并使用。 这个过程需要两个步骤:

2.1 将Token插入到所有表单

Springsecurity在JSP端预置了名为_csrf的Token字段,你只需要在jps的form中使用即可:

<form action="/login" method="post">
  <input type="text" name="username" />
  <input type="password" name="password" />
  <input type="submit" value="Login"/>
  <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>

在默认情况下,Spring Security的所有EndPoint或者controller都能够解析名为_csrf的token字段。

2.2 创建Token工厂和存储库

创建跨站点请求伪造保护所需的csrfTokenRepository Bean,详情请参考以下示例:

http.csrf()
    .csrfTokenRepository(csrfTokenRepository());

private CsrfTokenRepository csrfTokenRepository() {
    HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
    repository.setSessionAttributeName("_csrf");

    return repository;
}

此处使用了HttpSessionCsrfTokenRepository,用于将生成的token存储在当前用户的session中,如果Oauth2集成的话,使用的是OAuth2AuthorizedClientCsrfTokenRepository

以上便是Spring Security防护CSRF攻击的两种常见的方法。

示例1:

在Spring Security中使用CsrfToken进行跨站请求伪造保护:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/css/**", "/index").permitAll().antMatchers("/user/**")
                .hasRole("USER").and().formLogin().loginPage("/login").failureUrl("/login-error")
                .and().exceptionHandling().accessDeniedPage("/401");

        http.csrf().csrfTokenRepository(csrfTokenRepository());
    }

    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setSessionAttributeName("_csrf");

        return repository;
    }
}

在JSP的表单中,将_csrf的Token属性作为隐藏的字段:

<form th:action="@{/logout}" method="post">
    <input type="submit" value="Log out" />
    <input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
</form>

示例2:

在Spring Security中使用SameSite来防范跨站请求伪造攻击。

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {  
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/css/**", "/index").permitAll().antMatchers("/user/**")
                .hasRole("USER").and().formLogin().loginPage("/login").failureUrl("/login-error")
                .and().exceptionHandling().accessDeniedPage("/401");

        http.csrf().requireCsrfProtectionMatcher(new CSRFRequireSamesiteMatcher());
    }
}

public class CSRFRequireSamesiteMatcher implements RequestMatcher {
    private static final Pattern ALLOWED_METHODS = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
    private static final Pattern API_PATTERN = Pattern.compile("^/api(?!/auth).*$");

    private static final String STRICT = "Strict";

    @Override
    public boolean matches(HttpServletRequest request) {
        String path = request.getRequestURI();
        if (ALLOWED_METHODS.matcher(request.getMethod()).matches() || API_PATTERN.matcher(path).matches()) {
            return false;
        }
        String samesite = request.getHeader("Cookie");
        return samesite != null && !containsToken(samesite, STRICT);
    }

    private boolean containsToken(String samesite, String token) {
        String[] tokens = samesite.split(";");
        for (String t : tokens) {
            if (t.trim().startsWith(token)) {
                return true;
            }
        }
        return false;
    }
}

以上即为Spring Security中防护CSRF的常见方法。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:SpringSecurity跨域请求伪造(CSRF)的防护实现 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Spring Security使用数据库登录认证授权

    下面我将为您讲解如何使用Spring Security实现数据库登录认证和授权。 一、引入依赖 首先,需要在pom.xml文件中引入Spring Security依赖: <dependency> <groupId>org.springframework.security</groupId> <artifactId&g…

    Java 2023年6月3日
    00
  • 小程序的上传文件接口的注意要点解析

    小程序的上传文件接口用于将本地客户端的文件上传到服务器,具体操作过程如下: 请求方式 上传文件接口的请求方式为POST请求。 请求地址 上传文件接口的地址为 https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE。 其中,ACCESS_TOK…

    Java 2023年5月23日
    00
  • 对象引用的作用是什么?

    在Java中,对象引用是一种特殊的数据类型,用于存储对象在内存中的地址。对象引用的作用是指向对象在内存中的位置,从而可以访问对象的属性和方法。以下是对象引用的完整使用攻略: 1. 声明对象引用 在Java中,使用类名或接口名来声明对象引用。以下是一个声明对象引用的示例: public class ObjectReferenceExample { public…

    Java 2023年5月12日
    00
  • 一文带你你搞懂Java的3种IO模型

    一文带你搞懂Java的3种IO模型 在Java中,输入输出操作是很常见的。Java的IO模型可以分为三种:Blocking IO、Non-blocking IO和异步IO。它们的区别在于处理IO事件的方式不同。 Blocking IO 在Blocking IO模型中,当向Socket写入数据时,线程会阻塞,直到数据被真正写入。而当Socket读取数据时,线程…

    Java 2023年5月31日
    00
  • java实现的连接数据库及模糊查询功能示例

    以下是详细的攻略: 连接数据库 Java连接数据库需要使用JDBC(Java Database Connectivity)技术,具体过程如下: 导入JDBC驱动程序。如果使用MySQL数据库,则需要下载相应的驱动。可以在MySQL官网 下载最新版本的JDBC驱动。 加载驱动程序。可以使用Class.forName()方法来加载驱动程序。 建立数据库连接。使用…

    Java 2023年5月19日
    00
  • Java中网络IO的实现方式(BIO、NIO、AIO)介绍

    Java中网络IO的实现方式主要有BIO、NIO、AIO三种。下面分别进行介绍。 BIO BIO即Blocking IO,阻塞式IO,是一种传输方式。BIO的特点是同步阻塞,也就是说,客户端请求到来后,服务器必须处理完该请求才能执行下一步操作,高并发下无法满足需求。使用BIO方式,可以使用Socket和ServerSocket类进行通信。 下面是一个BIO的…

    Java 2023年5月19日
    00
  • Java实现二叉树的基本操作详解

    Java实现二叉树的基本操作详解 二叉树是一种非常常见的树形结构,由于它的具有良好的数据存储和查询性能,在实际开发中也经常使用到。本文将介绍如何使用Java语言实现二叉树的基本操作,包括构建二叉树、插入节点、删除节点、查找节点等功能。 二叉树节点的定义 首先,我们需要定义一个二叉树节点类,它包含三个属性,分别是节点值、左子节点和右子节点,定义如下: clas…

    Java 2023年5月19日
    00
  • Java面试题冲刺第十七天–基础篇3

    Java面试题冲刺第十七天–基础篇3 在第十七天的基础篇3中,主要讲解了Java中的接口和泛型,下面将从概念、用法和示例三个方面对这两个知识点进行详细讲解。 接口 概念 接口是一种特殊的抽象类,其中的所有方法默认都是抽象的,不能包含具体实现。接口可以被多个类实现,通过接口可以实现类与类之间的松耦合。 用法 在Java中,使用interface关键字来定义接…

    Java 2023年5月19日
    00
合作推广
合作推广
分享本页
返回顶部