当前位置: 首页 > 知识库问答 >
问题:

Spring Boot security无法禁用CSRF保护

秋阳旭
2023-03-14

我的Spring Boot REST API受KeyClope实例的保护。由于CSRF保护只允许GET和POST,我想禁用它。然而,我的方法似乎不起作用,因为REST API将为任何来源不同于的请求返回HTTP状态403http://localhost:8080.以下是我如何配置我的安全性:

package de.longnguyen.security;

import de.longnguyen.controller.KeycloakController;
import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver;
import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.session.SessionManagementFilter;


@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
    private static final String[] ALLOWED = new String[]{"/", "/static/**", "/v2/api-docs", "/swagger*/**", "/webjars/**"};

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    @Bean
    public KeycloakSpringBootConfigResolver KeycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
        web.ignoring()
                .antMatchers(ALLOWED);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        http
                .cors()
                .and()
                .authorizeRequests()
                .antMatchers(ALLOWED).permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .addFilterBefore(new CustomCorsFilter(), SessionManagementFilter.class)
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .csrf().disable();
    }
}

带有http://localhost:8080起源的请求将起作用:

编辑:

这就是我的CustomCorsFilter的样子:

package de.longnguyen.security;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.*;
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 CustomCorsFilter implements Filter {

    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) {
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;
            response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
            response.setHeader("Vary", "Origin");
            response.setHeader("Access-Control-Max-Age", "3600");
            response.setHeader("Access-Control-Allow-Credentials", "true");
            response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
            response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, X-CSRF-TOKEN");
        }
        chain.doFilter(req, res);
    }

    public void init(FilterConfig filterConfig) {
    }
}

编辑:

我的日志是这样的:

2020-03-26 23:08:45.758 DEBUG 27582 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/api/v1/keycloak/delete'; against '/'
2020-03-26 23:08:45.758 DEBUG 27582 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/api/v1/keycloak/delete'; against '/static/**'
2020-03-26 23:08:45.758 DEBUG 27582 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/api/v1/keycloak/delete'; against '/v2/api-docs'
2020-03-26 23:08:45.758 DEBUG 27582 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/api/v1/keycloak/delete'; against '/swagger*/**'
2020-03-26 23:08:45.758 DEBUG 27582 --- [nio-8080-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher  : Checking match of request : '/api/v1/keycloak/delete'; against '/webjars/**'
2020-03-26 23:08:45.758 DEBUG 27582 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/keycloak/delete at position 1 of 17 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2020-03-26 23:08:45.758 DEBUG 27582 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/keycloak/delete at position 2 of 17 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2020-03-26 23:08:45.758 DEBUG 27582 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/keycloak/delete at position 3 of 17 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2020-03-26 23:08:45.758 DEBUG 27582 --- [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : /api/v1/keycloak/delete at position 4 of 17 in additional filter chain; firing Filter: 'CorsFilter'
2020-03-26 23:08:45.759 DEBUG 27582 --- [nio-8080-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.springframework.http.ResponseEntity<java.lang.String> de.longnguyen.controller.KeycloakController.delete()
2020-03-26 23:08:45.760 DEBUG 27582 --- [nio-8080-exec-2] o.s.web.cors.DefaultCorsProcessor        : Reject: HTTP 'DELETE' is not allowed
2020-03-26 23:08:45.761 DEBUG 27582 --- [nio-8080-exec-2] o.s.s.w.header.writers.HstsHeaderWriter  : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@3fffd0ea
2020-03-26 23:08:45.761 DEBUG 27582 --- [nio-8080-exec-2] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed

共有2个答案

钱锐
2023-03-14

@这是不正确的。无论何时从浏览器发送跨域请求,浏览器都会向服务器发送飞行前请求,以读取Access Conrol Allow Origin标头。如果没有从服务器设置响应头,浏览器不会发送您的实际请求。人们使用的诀窍是不使用服务器,而是在客户端实现CORS中间件。就像angular应用程序中的HTTPInterceptor一样,它添加了一个访问控制Allow Origin=*响应头,并欺骗浏览器相信该头来自服务器。

闾丘书
2023-03-14

您可以尝试将您的方法更改为以下内容。

@Override
    public void configure(HttpSecurity http) throws Exception {
        http
            .csrf()
            .disable()
            .headers()
            .frameOptions()
            .disable()
        .and()
...
}

而不是添加. addFilter之前(新的CustomCorsFilter(),您可以在配置中创建一个Bean,如

@Bean
CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Collections.singletonList("*"));
    configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "DELETE", "PUT", "PATCH"));
    configuration.setAllowedHeaders(Arrays.asList("X-Requested-With", "Origin", "Content-Type", "Accept", "Authorization"));
    configuration.setAllowCredentials(true);
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}

SessionManagementFilter可能也是如此。

 类似资料:
  • 我有无类表单,使用GET方法,无法禁用csrf保护。我想使用GET方法,因为用户必须有选项来提供指向他/她的搜索的链接。当用户提交表单时,URL中会出现\u标记。如果其他用户尝试使用它,您知道,“CSRF令牌无效。请尝试重新提交表单。”出现。 这是控制器中的功能: 这是twig中的代码 我的Symfony版本是v2。8.45. 我试图通过csrf_protection= 我做错了什么? 编辑:嗯,

  • CSRF是指针对Web应用程序的跨站点伪造攻击。 CSRF攻击是系统的经过身份验证的用户执行的未授权活动。 因此,许多Web应用程序容易受到这些攻击。 Laravel以下列方式提供CSRF保护 - Laravel包含一个内置的CSRF插件,可为每个活动用户会话生成令牌。 这些令牌验证相关的经过身份验证的用户是否发送了操作或请求。 实现 (Implementation) 本节将详细讨论Laravel

  • 问题内容: 我正在构建一个通过webservices与symfony2应用程序对话的移动应用程序,我找不到在特定控制器/操作上禁用csrf保护的方法 我想将注册数据发布到此操作并使用sf2表单验证。我没有在移动应用程序中致电该表格 无法在操作中更改容器参数,因为它是冻结参数而引发异常… 我不想禁用整个应用程序的表单保护 有什么线索吗? 谢谢 ! 更新:使用symfony 2.1.x 问题答案: 如

  • 简介 Laravel 可以轻松地保护应用程序免受 跨站点请求伪造 (CSRF) 攻击,跨站点请求伪造是一种恶意攻击,它凭借已通过身份验证的用户身份来运行未经过授权的命令。 Laravel 会自动为每个活跃用户的会话生成一个 CSRF「令牌」。该令牌用于验证经过身份验证的用户是否是向应用程序发出请求的用户。 无论何时,当您在应用程序中定义HTML表单时,都应该在表单中包含一个隐藏的CSRF标记字段,

  • 我使用Spring Boot和Spring Security创建我的web项目。我想禁用特定URL模式的CSRF保护,为Android设备提供API。 使用 如何通过XML配置和 Spring Boot的第一种方法:仅对某些请求选择性地启用CSRF检查 我写了以下配置: 运行此项目时,我会出现以下错误: 上面的日志显示正则表达式在 在索引6/api/**附近有悬挂的元字符“*”。但我不知道这个错误

  • 问题内容: django csrf中间件无法禁用。我已经从我的项目的中间件中将其注释掉,但是由于缺少CSRF问题,导致登录失败。我正在使用Django主干。如果未在中间件中启用CSRF,如何引起问题? 我必须禁用它,因为CSRF刚刚中断了我站点上的许多POST请求。关于如何在django主干项目中完全禁用CSRF的任何反馈? Django主干中的“新” CSRF框架也破坏了一个外部站点,该站点正在