0

Several of my Spring Security based projects expose a RESTful API that support the full range of HTTP verbs: GET, POST, PUT, PATCH, DELETE, etc. For those projects only using GET and POST, everything works as expected. When using PUT, however, I encounter CSRF protection issues that usually lead me to disable CSRF protection.

My primary question is, "Why does Spring Security treat PUT and POST differently?"

My secondary question is, "Is disabling CSRF protection a real issue given that my projects are truly stateless, use no cookies and require a valid OAuth2 bearer token?"

I also have a secondary level of protection verifying that the bearer of the OAuth2 token is authorized to perform the requested action.

I suspect that PATCH and DELETE would encounter the same issue with CSRF protections in Spring Security but have not developed test-cases to validate my suspicions. We usually develop the PUT use-case before developing the others.

FWIW, this issue appears in Spring Security 4 and 5. I have some of both in my projects.

Faron
  • 103
  • 1

3 Answers3

0

By default, CSRF is only even possible for a few verbs - GET, POST, HEAD, and in some cases OPTIONS - because those are the only verbs possible for cross-site requests at all. Of those, only POST should ever change state on the server, although of course in practice people allow GET requests to change state all the time (logout CSRF via a GET request to //site.com/logout for example).

It is possible to enable CSRF risks for other verbs by configuring CORS on your server and allowing the remote site as an allowed "Origin", allowing the relevant verbs ("Methods"), and allowing Credentials (typically cookies) in the cross-site request. However, by default that's disabled, and even if you enable it you should only ever allow it for specific, trusted sites; essentially taking down some of the same-origin policy between your site and the allowed "Origin" because you trust them to be secure and non-malicious.

I don't know what Spring Security is doing for CSRF protection on non-GET/POST/HEAD requests, but if it's getting in your way and you haven't enabled CORS, you can safely turn it off for those requests only. There's also ways to just render CSRF a non-issue, such as using a bearer token (in the HTTP "Authorization" header) instead of cookies; bearer tokens aren't sent automatically, so they must be manually included via script, and if the attacker can do that then they just already know the victim's session token and there's no need to forge a request from the victim's browser. The "SameSite" cookie flag can also block most CSRF risks, although it's not supported on very old browsers and also in "Lax" mode it doesn't protect against CSRF via top-level GET requests (i.e. setting window.location) although it does still protect against GET-based CSRF via things like iframes or image tags (and also you shouldn't have state-changing GET requests anyhow...).

CBHacking
  • 40,303
  • 3
  • 74
  • 98
0

Without further details on what kind of "CSRF protection issues" you are running into, it's hard to say why POST and PUT would be different here. Do you mean that POST requests to your API go right through without any token, but PUT requests raise an exception nagging about a missing token? Could you elaborate on that point a bit?

Spring security, when CSRF protection is enabled, expects the token in an urlencoded body parameter named _csrf or a header named X-CSRF-TOKEN.

Anyway, CSRF is an an issue only when you use cookies for session management. Feel free to disable it if you're not using cookies.

0

My secondary question is, "Is disabling CSRF protection a real issue given that my projects are truly stateless, use no cookies and require a valid OAuth2 bearer token?"

No, CSRF is only useful for cookie-based authentication. APIs using Bearer tokens or any other custom-header-based authentication should not enforce CSRF

When using PUT, however, I encounter CSRF protection issues that usually lead me to disable CSRF protection. My primary question is, "Why does Spring Security treat PUT and POST differently?"

It could be a programming issue on your application. Spring enforces CSRF on any methods except GET,HEAD,OPTIONS. But probably the fact that you are using OAuth tokens explains, at least partially, why you are not sending CSRF header along.

usr-local-ΕΨΗΕΛΩΝ
  • 5,310
  • 2
  • 17
  • 35