4

I'm trying to implement CSRF token security in my Spring Boot API to learn how to deal with that.

I've followed this tutorial (server side part) and this is my security config:

private static final String[] CSRF_IGNORE = {"/api/login"};


protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf()
                .ignoringAntMatchers(CSRF_IGNORE)
                .csrfTokenRepository(csrfTokenRepository())
                .and()
                .addFilterAfter(new CustomCsrfFilter(), CsrfFilter.class)
                .exceptionHandling()
                .authenticationEntryPoint(new Http403ForbiddenEntryPoint() {
                })
                .and()
                .authenticationProvider(getProvider())
                .formLogin()
                .loginProcessingUrl("/api/login")
                .successHandler(new AuthentificationLoginSuccessHandler())
                .failureHandler(new SimpleUrlAuthenticationFailureHandler())
                .and()
                .logout()
                .logoutUrl("/api/logout")
                .logoutSuccessHandler(new AuthentificationLogoutSuccessHandler())
                .invalidateHttpSession(true)
                .and()
                .authorizeRequests()
                .anyRequest().authenticated();
    }

Others things are the same as in the tutorial.

I'm testing with Postman.

When i add the endpoint i want in CSRF_IGNORE, i can see with logger/debug that token stocked, and token from cookie are the same, because the security config's part CustomCsrfFilter.java in .addFilterAfter() is used, but when i remove the endpoint from this CSRF_IGNORE, what i get is a 403, and, logger/debug in the CustomCsrfFilter.java isn't used, so i'm thinking that tokens aren't compared.

I think I missed something and I would like to understand.

Thomas
  • 55
  • 1
  • 6

2 Answers2

2

If you want to use CSRF with a http only false cookie, why not use Spring Security's built in CookieCsrfTokenRepository? Should simplify your config that way. CustomCsrfFilter seems to be adding a XSRF-TOKEN cookie to the HttpServletResponse, which CookieCsrfTokenRepository does for you.

The default CSRF cookie name when using CookieCsrfTokenRepository is X-CSRF-TOKEN, which is conveniently the default name Angular's HttpClientXsrfModule uses. Of course you can customize that if you need.

So your security config becomes:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf()
                    .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and()
                .exceptionHandling()
                    .authenticationEntryPoint(new Http403ForbiddenEntryPoint())
                .and()
                    .authenticationProvider(getProvider())
                .formLogin()
                    .loginProcessingUrl("/api/login")
                    .successHandler(new AuthentificationLoginSuccessHandler())
                    .failureHandler(new SimpleUrlAuthenticationFailureHandler())
                .and()
                .logout()
                    .logoutUrl("/api/logout")
                    .logoutSuccessHandler(new AuthentificationLogoutSuccessHandler())
                    .invalidateHttpSession(true)
                .and()
                .authorizeRequests()
                    .anyRequest().authenticated();
    }

And with Angular, your app module has HttpClientXsrfModule as

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    HttpClientXsrfModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
drumonii
  • 343
  • 5
  • 15
  • Hi, thanks for your answer. Before to ask help, i tried with the built in `CookieCsrfTokenRepository`, but it was the same. Now, to do it the right way, I tried to do like you said, and it's more simple than adding a csrf token repository. I also deleted my custom csrf filter from the security config. Now, i'm on the same problem. Post request on endpoints who are not in the `.ignoringAntMatchers` gives me a 403 error. Do you have any idea ? – Thomas Apr 21 '20 at 10:03
  • 3
    Nevermind, it's working now, i just had to add in headers (in postman) the X-XSRF-TOKEN. Now, if i have understand, i need send in my front, in headers, the token wich is in the cookie. – Thomas Apr 21 '20 at 10:38
  • Thanks @Thomas this helped me a lot, adding that header in postman request :) – Biafra Oct 13 '20 at 10:10
  • @drumonii, This is unrelated to your answer, but do you happen to remember how to get your security config format like that? you doing it manually or do you have a formatting config you use to set that? I've never been able to find it. – Brent Thoenen Dec 10 '20 at 20:54
  • 1
    @BrentThoenen, I formatted it manually. You may want to use `// @formatter:off` and `// @formatter:on` so that your IDE ignores those config lines when you format the entire security config class. – drumonii Dec 13 '20 at 19:40
  • @drumonii, I have tried implementing the csrftokenrepository along with sending the header X-XSRF-TOKEN in the request header while sending the POST request in POSTMAN but I am still getting 403 Forbidden error. Please find below the code snippet in my configuration file: http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and().authorizeHttpRequests().antMatchers(HttpMethod.POST, "/secure/register").permitAll(); – Iqbal Jul 07 '22 at 02:44
  • @Iqbal it's hard to tell without seeing your full code and your request. might suggest posting your own question and linking here – drumonii Jul 30 '22 at 02:39
0

Even though this question is kind of old, I've been struggling with the same issue for the last couple of days. A lot of people suggest to add:

       <th:input type="hidden" name="${_csrf.parameterName}"
                        value="${_csrf.token}" />

into your form. Despite of that, the csrf-token isn't send. For me the problem was solved by moving the html-file, containing the form into the template folder of my Spring Boot project. It seems as if thymeleaf is only then able to add the csrf-token automatically.