Spring Security blocks POST requests despite SecurityConfig

后端 未结 3 1072
囚心锁ツ
囚心锁ツ 2021-02-12 15:27

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-con

相关标签:
3条回答
  • 2021-02-12 16:09

    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

    0 讨论(0)
  • 2021-02-12 16:09

    Cross-site request forgery is a web security vulnerability that allows an attacker to induce users to perform actions that they do not intend to perform.

    In your case disabling CSRF protection exposes user to this vulnerability.

    Note: If it was pure Rest API with O-Auth protection then CSRF was not needed. Should I use CSRF protection on Rest API endpoints?

    But In your case when user logs in a session is created and cookie is returned in response and without CSRF token Attacker can exploit it and perform CSRF.

    It wouldn't be a good idea to disable CSRF instead you can configure your app to return CSRF token in response headers and then use it in all your subsequent state changing calls.

    Add this line of code in your SecurityConfiguration.java

    // CSRF tokens handling
    http.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class);
    

    CsrfTokenResponseHeaderBindingFilter.java

    public class CsrfTokenResponseHeaderBindingFilter extends OncePerRequestFilter {
        protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf";
        protected static final String RESPONSE_HEADER_NAME = "X-CSRF-HEADER";
        protected static final String RESPONSE_PARAM_NAME = "X-CSRF-PARAM";
        protected static final String RESPONSE_TOKEN_NAME = "X-CSRF-TOKEN";
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, javax.servlet.FilterChain filterChain) throws ServletException, IOException {
            CsrfToken token = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME);
    
            if (token != null) {
                response.setHeader(RESPONSE_HEADER_NAME, token.getHeaderName());
                response.setHeader(RESPONSE_PARAM_NAME, token.getParameterName());
                response.setHeader(RESPONSE_TOKEN_NAME, token.getToken());
            }
    
            filterChain.doFilter(request, response);
        }
    }
    

    Header Response form Server:

    Note that we now have CSRF token in the header. This will not change untill the session expires. Also read: Spring Security’s CSRF protection for REST services: the client side and the server side for better understanding.

    0 讨论(0)
  • 2021-02-12 16:20

    Its simple CSRF enabled issue that doesn't allow POST requests. I faced the same problem here's the solution:(Explained)

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers(HttpMethod.POST,"/form").hasRole("ADMIN")  // Specific api method request based on role.
                .antMatchers("/home","/basic").permitAll()  // permited urls to guest users(without login).
                .anyRequest().authenticated()
                .and()
            .formLogin()       // not specified form page to use default login page of spring security
                .permitAll()
                 .and()
            .logout().deleteCookies("JSESSIONID")  // delete memory of browser after logout
    
            .and()
            .rememberMe().key("uniqueAndSecret"); // remember me check box enabled.
    
        http.csrf().disable();  **// ADD THIS CODE TO DISABLE CSRF IN PROJECT.**
    }
    

    Above code:

    http.csrf().disable();

    will solve the problem.

    0 讨论(0)
提交回复
热议问题