尽管有 SecurityConfig,Spring Security 仍会阻止 POST 请求 [英] Spring Security blocks POST requests despite SecurityConfig

查看:29
本文介绍了尽管有 SecurityConfig,Spring Security 仍会阻止 POST 请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发基于 Spring Boot (spring-boot-starter-web) 的 REST API,其中我使用 Spring Security (spring-security-core e spring-security-config) 来保护不同的端点.

身份验证是通过使用包含具有两组不同角色的用户的本地数据库完成的:ADMINUSER.USER 应该能够GET 所有 API 端点并POST 到基于routeA 的端点.ADMIN 应该能够与USER 加上POSTDELETE 对基于`routeB

但是我得到的行为是我可以对任何端点执行 GET 请求,但 POST 请求总是返回 HTTP 403 Forbidden任一类型的用户 - ADMINUSER - 根据我的 SecurityConfiguration,这不是我所期望的.

对我缺少什么有任何想法吗?

<小时>

SecurityConfiguration.java

@Configuration@启用网络安全公共类 SecurityConfiguration 扩展了 WebSecurityConfigurerAdapter {私有静态最终记录器记录器 = LoggerFactory.getLogger(SecurityConfiguration.class);@自动连线私有 RESTAuthenticationEntryPoint authenticationEntryPoint;@自动连线私有数据源数据源;@覆盖public void configure(AuthenticationManagerBuilder builder) 抛出异常 {logger.info("使用数据库作为身份验证提供者.");builder.jdbcAuthentication().dataSource(dataSource).passwordEncoder(new BCryptPasswordEncoder());}@覆盖protected void configure(HttpSecurity http) 抛出异常 {http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers(HttpMethod.GET, "/**").hasAnyRole("ADMIN", "USER").antMatchers(HttpMethod.POST, "/routeA/*").hasAnyRole("ADMIN", "USER").antMatchers(HttpMethod.POST, "/routeB/*").hasRole("ADMIN").antMatchers(HttpMethod.DELETE, "/routeB/*").hasRole("ADMIN").and().requestCache().requestCache(new NullRequestCache()).and().httpBasic().authenticationEntryPoint(authenticationEntryPoint).and().cors();}@豆公共 CorsConfigurationSource corsConfigurationSource() {最终 CorsConfiguration 配置 = new CorsConfiguration();configuration.setAllowedOrigins(Arrays.asList("*"));configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));configuration.setAllowCredentials(true);configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));最终 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", 配置);返回源;}

RouteBController .java

@RestController公共类 RouteBController {静态最终记录器记录器 = LoggerFactory.getLogger(RouteBController.class);公共 RouteBController() { }@RequestMapping(value = "routeB",产生 = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET)公共字符串 getStuff() {return "有一个你好世界!";}@RequestMapping(value = "routeB",产生 = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)公共字符串 postStuff() {return "发布了一个你好世界!";}}

RESTAuthenticationEntryPoint.java

@Component公共类 RESTAuthenticationEntryPoint 扩展 BasicAuthenticationEntryPoint {@覆盖public void afterPropertiesSet() 抛出异常 {setRealmName("AppNameHere");super.afterPropertiesSet();}}

解决方案

BEFORE 禁用 CSFR 作为解决此问题的一种方式,请查看 Mohd Waseem 的回答 以更好地理解为什么它很重要并了解如何正确设置它.正如 RCaetano 所说CSFR 是来帮助我们抵御攻击的,不应盲目禁用它.

由于这个答案仍然解释了我最初问题中的两个问题,我将其作为标记答案,以提高人们对 CSFT 和安全路线可能存在的问题的认识,但不要从字面上理解.


SecurityConfiguration.java 中有 2 个问题使其行为异常.

虽然 403 Forbidden 错误消息没有包含任何关于失败原因的消息指示(参见下面的示例),但事实证明这是由于 CSRF 已启用.禁用它允许处理 POSTDELETE 请求.

<代码>{时间戳":2018-06-26T09:17:19.672+0000",状态":403,错误":禁止",消息":禁止",路径":/routeB";}

还有 antMatched(HttpMethod, String) 中用于 RouteB 的表达式是不正确的,因为 /routeB/* 期望它具有 / 之后的>东西.正确的配置是 /routeB/** 因为更多路径可以存在(或不).


更正的 SecurityConfiguration.java

@Overrideprotected void configure(HttpSecurity http) 抛出异常 {http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers(HttpMethod.GET, "/**").hasAnyRole("ADMIN", "USER").antMatchers(HttpMethod.POST, "/routeA/**").hasAnyRole("ADMIN", "USER").antMatchers(HttpMethod.POST, "/routeB/**").hasRole("ADMIN").antMatchers(HttpMethod.DELETE, "/routeB/**").hasRole("ADMIN").and().requestCache().requestCache(new NullRequestCache()).and().httpBasic().authenticationEntryPoint(authenticationEntryPoint).and().cors().and().csrf().disable();}


<块引用>

来源: StackOverflow em Português

I'm developing a REST API based on Spring Boot (spring-boot-starter-web) where I use Spring Security (spring-security-core e spring-security-config) to protect the different endpoints.

The authentication is done by using a local database that contains users with two different sets of roles: ADMIN andUSER. USER should be able toGET all API endpoints and POST to endpoints based onrouteA. ADMIN should be able to do the same asUSER plus POST andDELETE to endpoints based on `routeB

However the behavior I'm getting is that I can do GET requests to any endpoint but POST requests always return HTTP 403 Forbidden for either type of user - ADMIN and USER - which is not expected what I'm expecting based on my SecurityConfiguration.

Any ideas of what am I missing?


SecurityConfiguration.java

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(SecurityConfiguration.class);

    @Autowired
    private RESTAuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    private DataSource dataSource;

    @Override
    public void configure(AuthenticationManagerBuilder builder) throws Exception {
        logger.info("Using database as the authentication provider.");
        builder.jdbcAuthentication().dataSource(dataSource).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().
            authorizeRequests().antMatchers(HttpMethod.GET, "/**").hasAnyRole("ADMIN", "USER")
                               .antMatchers(HttpMethod.POST, "/routeA/*").hasAnyRole("ADMIN", "USER")
                               .antMatchers(HttpMethod.POST, "/routeB/*").hasRole("ADMIN")
                               .antMatchers(HttpMethod.DELETE, "/routeB/*").hasRole("ADMIN").and().
            requestCache().requestCache(new NullRequestCache()).and().
            httpBasic().authenticationEntryPoint(authenticationEntryPoint).and().
            cors();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

RouteBController .java

@RestController
public class RouteBController {

    static final Logger logger = LoggerFactory.getLogger(RouteBController.class);

    public RouteBController() { }

    @RequestMapping(value = "routeB", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET)
    public String getStuff() {
        return "Got a hello world!";
    }

    @RequestMapping(value = "routeB", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)
    public String postStuff() {
        return "Posted a hello world!";
    }

}

RESTAuthenticationEntryPoint.java

@Component
public class RESTAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {

    @Override
    public void afterPropertiesSet() throws Exception {
        setRealmName("AppNameHere");
        super.afterPropertiesSet();
    }
}

解决方案

BEFORE disabling the CSFR as a way of fixing this issue, please check the resources on Mohd Waseem's answer to better understand why it is important and to have an idea of how it can be properly set up. As RCaetano has said, CSFR is here to help us from attacks and it should not be disabled blindly.

Since this answer still explained the 2 issues on my original questions, I'll leave it as the marked answer to create awareness about possible issues with the CSFT and security routes but don't take it literally.


There were 2 issues in SecurityConfiguration.java that made it misbehave.

Although the 403 Forbidden error message didn't contain any message indication of why it was failing (see example below) it turns out it was due to having CSRF enabled. Disabling it allowed for POST and DELETE requests to be processed.

{
    "timestamp": "2018-06-26T09:17:19.672+0000",
    "status": 403,
    "error": "Forbidden",
    "message": "Forbidden",
    "path": "/routeB"
}

Also the expression used in antMatched(HttpMethod, String) for RouteB was incorrect because /routeB/* expects it to have something after /. The correct configurtion is /routeB/** since more paths can be present (or not).


The corrected SecurityConfiguration.java is

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().
        authorizeRequests().antMatchers(HttpMethod.GET, "/**").hasAnyRole("ADMIN", "USER")
                           .antMatchers(HttpMethod.POST, "/routeA/**").hasAnyRole("ADMIN", "USER")
                           .antMatchers(HttpMethod.POST, "/routeB/**").hasRole("ADMIN")
                           .antMatchers(HttpMethod.DELETE, "/routeB/**").hasRole("ADMIN").and().
        requestCache().requestCache(new NullRequestCache()).and().
        httpBasic().authenticationEntryPoint(authenticationEntryPoint).and().
        cors().and().
        csrf().disable();
}


Source: StackOverflow em Português

这篇关于尽管有 SecurityConfig,Spring Security 仍会阻止 POST 请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆