spring-projects / spring-security

Spring Security
http://spring.io/projects/spring-security
Apache License 2.0
8.75k stars 5.88k forks source link

CsrfAuthenticationStrategy with stateless double submit CSRF token not working as intended? #5669

Closed high-stakes closed 6 years ago

high-stakes commented 6 years ago

Summary

Hi,

CsrfAuthenticationStrategy only seems to support stateful csrf setups as it creates a new token on each authentication as in stateless setups onauthenticate is called for each request. Considering the recommended CSRF token repository for Angular apps (which usually use stateless token based authentication) is the CookieCsrfTokenRepository which uses the stateless double submit cookie validation pattern, this looks like erroneous behavior as in stateless mode I would not expect to have a new CSRF token generated every request.

Actual Behavior

When using CookieCsrfTokenRepository in a stateless setting the CSRF token is recreated on each request because onAuthenticate is always triggered due to no active session found

Expected Behavior

because the token is stateless it is only recreated when no CSRF cookie is sent in the response when there is no http session. The token should not be tied to authentication.

Configuration

http
    .authorizeRequests()
        .anyRequest().authenticated()
    .and()
    .sessionManagement()
           .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    .and()
    .addFilterBefore(new CustomAuthenticationTokenFilter(), AnonymousAuthenticationFilter.class);
    .csrf()
        .csrfTokenRepository(new CookieCsrfTokenRepository());

Version

Spring boot 2.0.3

rwinch commented 6 years ago

@high-stakes Thanks for the feedback.

CsrfAuthenticationStrategy only applies to after a user successfully authenticates. This is intended to avoid attacks similar to a session fixation attack where a malicious user establishes a valid CSRF token and then tricks a user into authenticating and then using the CSRF token from prior to authentication.

I'm not sure I understand your use case. Can you explain what you are trying to do in terms of HTTP request/responses?

high-stakes commented 6 years ago

Hi @rwinch ,

My question is basically in the case of a sessionless application which uses an authentication token that is verified on each request and triggers the onAuthentication method on each request causing a new CSRF token to be generated always even though the user is already "authenticated" (not in a stateful sense though just from the client pov).

Now with the double submit CSRF token solution which is stateless the only thing that is verified if the request header matches the request csrf cookie. The potential of token fixation does not decrease in this case by only sending it when authenticated because you don't check the session contents to verify the csrf token.

I was just wondering if this is intended as it seems accidental to tie a stateless verification to the authentication state. There is also no added benefit of having a new CRSF token on each request in this case because the client can construct a valid request without any backend interaction.

rwinch commented 6 years ago

It is quite deliberate that the CSRF token changes on authentication success. This is necessary.

Can you expand on what you mean by stateless? If you are using authentication that is not included by a browser automatically (i.e. an OAuth token), then you do not need to enable CSRF protection. However, if you are using something like HTTP Basic, there is still a risk.

fenceposterror commented 6 years ago

@rwinch If a server keeps track of the session, that is what I would assume @high-stakes means with stateful. If the server doesn't keep track of the session, then that would be stateless. For example in the case of a JWT token. @high-stakes, please correct me if I'm wrong.

So in case someone is using e.g. JWT tokens as a method to authenticate his or her requests, it feels unnecessary to change tokens each time, because the server doesn't keep track anyway of the session, or did I miss something?

rwinch commented 6 years ago

As I mentioned before stateless does not necessarily mean that you are immune to CSRF attacks.

If you are authenticating in a way that does not require CSRF tokens, then you can disable it and it will not be rotated. If you are using an authentication mechanism that requires CSRF tokens, then you must rotate on authentication success.

I'm closing this as there doesn't seem to be new information here. Either enable CSRF protection if you need it or disable it if you don't. If you need CSRF protection, then you need to rotate the token on log in.

lburja commented 3 years ago

For reference, if others run into this, you can use httpSecurity.csrf().sessionAuthenticationStrategy(new NullAuthenticatedSessionStrategy()) to work around this issue.

jalik commented 3 years ago

@lburja Dude, thank you so much for your help. I was trying to make Spring work with a SPA based on React, in which case we obviously don't want to have a different CSRF token generated on every single AJAX request... a thing that @rwinch seemed to not understand being blocked on token rotation during auth, while @high-stakes was talking about requests post auth.

OtenMoten commented 1 year ago

In a stateless Spring Boot security application with OAuth 2 bearer authorisation via JWT, you do not need to implement Cross-Site Request Forgery (CSRF) protection. CSRF protection is primarily relevant for applications that use session-based authentication.

Stateless authentication, such as OAuth 2 Bearer token authorisation via JWT, does not rely on server-side sessions. Instead, each request contains all the necessary authentication information in the form of a JWT token, typically in the Authorization header. As there is no session associated with the server, there is no need for CSRF protection.

CSRF attacks work by exploiting the trust that a user's browser has with a particular website, using the session information to make unauthorised requests on the user's behalf. With stateless authentication, there is no session data to exploit in this way, making CSRF attacks ineffective against such applications.

However, it's important to ensure that you handle JWT tokens securely to prevent other types of attacks, such as token leakage or man-in-the-middle attacks. Always follow best practices for securing JWT tokens, such as using HTTPS for communication, validating the token signature, and setting appropriate token expiration times.

In summary, CSRF protection is not required for stateless Spring Boot Security applications that use OAuth 2 Bearer authorisation via JWT. Instead, focus on proper JWT token management and overall application security to ensure a robust and secure authentication mechanism.

maxmmin commented 1 year ago

@lburja thank for your answer, i love you man. You made my day and mood so much better. Thank you man❤️

claudiumaravela commented 3 months ago

@OtenMoten you’re completely right, but if you’re generating that token in your backend and you store it as a httpOnly secure cookie, then you’re vulnerable to csrf, right? Because that secure cookie is attached to all the requests (by the browser).

OtenMoten commented 3 months ago

@OtenMoten you’re completely right, but if you’re generating that token in your backend and you store it as a httpOnly secure cookie, then you’re vulnerable to csrf, right? Because that secure cookie is attached to all the requests (by the browser).

@claudiumaravela

In a previous comment, I mentioned that "In a stateless Spring Boot security application with OAuth 2 bearer authorization via JWT, you do not need to implement Cross-Site Request Forgery (CSRF) protection." While this is true for scenarios where JWT tokens are passed in the Authorization header and not stored in cookies, it does not hold if the tokens are stored as httpOnly secure cookies.

If you store your JWT token in an httpOnly secure cookie, you are vulnerable to CSRF attacks because the browser attaches the secure cookie to all requests made to the same domain. This means an attacker could craft a malicious request to exploit the user's authenticated session.

To mitigate CSRF attacks in this scenario, you should implement CSRF protection mechanisms. One common approach is the double-submit cookie pattern, where a CSRF token is sent both as a cookie and as a request header. The server then verifies that the values match.

If you generate a token in your backend and store it as an httpOnly secure cookie, you are vulnerable to CSRF attacks. This vulnerability arises because the secure cookie is automatically included in all requests by the browser, allowing potential attackers to exploit it. Therefore, you need to implement CSRF protection to safeguard against such attacks.