Skip to content

Ineffective CSRF Protection for SPAs as suggested by the Official Docs? #15092

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ptrckkk opened this issue May 17, 2024 · 3 comments
Closed
Assignees
Labels
in: docs An issue in Documentation or samples status: invalid An issue that we don't feel is valid type: bug A general bug

Comments

@ptrckkk
Copy link

ptrckkk commented May 17, 2024

Describe the bug
The offical documentation for CSRF protection for Single Page Applications (SPA) might be ineffective. It seems possible to send arbitrary CSRF tokens which are accepted as valid CSRF tokens.

To Reproduce
I created a repository with a simple REST controller, having one POST endpoint at "/hello" which returns the plain text "Hello there".
The endpoint is protected by Spring Security in version 6.2.4 and configured exactly as the above-mentioned official docs recommend for SPAs.

If you start the application and send the following POST request via curl

curl -X POST http://localhost:8080/hello --cookie "XSRF-TOKEN=123" --header "X-XSRF-TOKEN: 123"

the backend will respond with "Hello, there" meaning the endpoint was reached and executed. However, "123" is not a valid CSRF token! Actually, when one changes "123" to any arbitrary value for both, the "XSRF-TOKEN" cookie and the "X-XSRF-TOKEN" header, the endpoint is executed.

Expected behavior
The expected behavior is that the curl request with arbitrary CSRF tokens runs into "invalid CSRF token" and does not execute the endpoint; thus, no "Hello, there" should be returned.

Sample

See "To reproduce".

@ptrckkk ptrckkk added status: waiting-for-triage An issue we've not yet triaged type: bug A general bug labels May 17, 2024
@jzheaux jzheaux added in: web An issue in web modules (web, webmvc) and removed status: waiting-for-triage An issue we've not yet triaged type: bug A general bug labels May 21, 2024
@jzheaux jzheaux self-assigned this May 21, 2024
@sjohnr
Copy link
Contributor

sjohnr commented May 23, 2024

@ptrckkk thanks for reaching out!

If you start the application and send the following POST request via curl

curl -X POST http://localhost:8080/hello --cookie "XSRF-TOKEN=123" --header "X-XSRF-TOKEN: 123"

the backend will respond with "Hello, there" meaning the endpoint was reached and executed.

Please be aware that using curl in this way does not simulate normal browser behavior. While you can specify arbitrary cookie and header values using curl, browsers will prevent sending arbitrary cookie values (via a Cookie header) in the request. Also be aware that the behavior you're referring to is specific to CookieCsrfTokenRepository and not just the documentation example. There is not an issue with the behavior of the cookie-based implementation.

In the future, if you feel you have found a security issue, please report it responsibly. Please also spend some time reading the Cross Site Request Forgery chapter in the reference and other resources covering CSRF and web application security.

I'm going to close this issue with the above explanation, as others have noted concern over this issue while it remains unresolved.

@sjohnr sjohnr closed this as completed May 23, 2024
@sjohnr sjohnr added status: invalid An issue that we don't feel is valid in: docs An issue in Documentation or samples type: bug A general bug and removed in: web An issue in web modules (web, webmvc) labels May 23, 2024
@sjohnr sjohnr assigned sjohnr and unassigned jzheaux May 23, 2024
@ptrckkk
Copy link
Author

ptrckkk commented May 26, 2024

In the future, if you feel you have found a security issue, please report it responsibly.

First of all, I did not intend to report a possible security issue irresponsibly and am now aware of how to do it more responsibly in the future!

I still do not understand why everything works as expected which is why I ask further questions.

  1. Also be aware that the behavior you're referring to is specific to CookieCsrfTokenRepository and not just the documentation example.

If I do not get it wrong, the documentation example uses csrfTokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse()which I use in my example, too, see my SecurityConfig. This leads me to the conclusion that I do not understand what you mean. Could you elaborate more on that?

  1. There is not an issue with the behavior of the cookie-based implementation.

I do not want to argue with that statement.
SPAs might use an API provided by a backend which does not rely on cookies. I assumed that the CSRF protection works independent of whether cookies are used or not. The documentation for this SPA section says

Configure a custom CsrfTokenRequestHandler that resolves the CSRF token based on whether it is an HTTP request header (X-XSRF-TOKEN) or request parameter (_csrf).

Thus, I would assume that it works with header parameters - and without any cookies.

These are my open questions.

Maybe the documentation could be extended how to do CSRF protection for SPAs that use an API backend not relying on cookies?

@sjohnr
Copy link
Contributor

sjohnr commented May 28, 2024

I still do not understand why everything works as expected which is why I ask further questions.

I am sorry you are not understanding. However, it feels like these are questions that would be better suited to Stack Overflow. We prefer to use GitHub issues only for bugs and enhancements. Feel free to update this issue with a link to the re-posted question (so that other people can find it).

Maybe the documentation could be extended how to do CSRF protection for SPAs that use an API backend not relying on cookies?

I believe this request does not account for how CSRF protection works, which relies on both a storage mechanism for the expected CSRF token (session or cookie) as well as an actual (resolved) token value (HTTP header or parameter). As I mentioned above, please spend some time understanding how CSRF protection works by reviewing the documentation (linked in my earlier comment).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: docs An issue in Documentation or samples status: invalid An issue that we don't feel is valid type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants