234

Quick note: this is not a duplicate of CSRF protection with custom headers (and without validating token) despite some overlap. That post discusses how to perform CSRF protection on Rest endpoints without discussing if it is actually necessary. Indeed, many CSRF/Rest questions I've read on this site talk about securing the endpoints via CSRF tokens without actually discussing whether or not it is necessary. Hence this question.

Is CSRF Protection necessary for Rest API endpoints?

I've seen lots of discussion about securing REST endpoints against CSRF attacks, but having given the topic lots of thought, I'm very certain that CSRF tokens on a REST endpoint grant zero additional protection. As such, enabling CSRF protection on a REST endpoint just introduces some useless code to your application, and I think it should be skipped. I may be missing something though, hence this question. I think it will help to keep in mind why CSRF protection is necessary in the first place, and the attack vectors it protects against:

Why CSRF?

It really boils down to the browsers ability to automatically present login credentials for any request by sending along cookies. If a session id is stored in a cookie the browser will automatically send it along with all requests that go back to the original website. This means that an attacker doesn't actually have to know authentication details to take an action as the victim user. Rather, the attacker just has to trick the victims browser into making a request, and the credentials to authenticate the request will ride along for free.

Enter a REST API

Rest API endpoints have a very important difference from other requests: they are specifically stateless, and should never accept/use data from either a cookie or session. As a result, a REST API that sticks to the standard is automatically immune to such an attack. Even if a cookie was sent up by the browser, any credentials associated with the cookie would be completely ignored. Authentication of calls to a REST API are done in a completely different fashion. The most common solution is to have some sort of authentication key (an OAuth Token or the like) which is sent along in the header somewhere or possibly in the request body itself.

Since authentication is application-specific, and since the browser itself doesn't know what the authentication token is, there is no way for a browser to automatically provide authentication credentials even if it is somehow tricked into visiting the API endpoint. As a result, a cookie-less REST endpoint is completely immune from CSRF attacks.

Or am I missing something?

Conor Mancone
  • 29,899
  • 13
  • 91
  • 96
  • Some REST API are limiting calls per ip, that may be an edge case where it could make sense to implement a csrf protection. – Xavier59 Aug 03 '17 at 18:51
  • 1
    Thanks for the input @Xavier59. Do you mind clarifying: why would rate limiting necessitate CSRF protection? – Conor Mancone Aug 03 '17 at 19:01
  • So I'm not confident that this is necessarily applicable to your case, but let's say you use google as an oauth provider. Your user logs in to some malicious site which also uses google as an oauth provider. The malicious site could use the user's token (ish, depending on client settings and such) for your site. See here for more: https://spring.io/blog/2011/11/30/cross-site-request-forgery-and-oauth2 – Jesse K Aug 03 '17 at 19:02
  • @ConorMancone If site `A` has a REST API limiting call per ip to 1/second, an attacker could trick Bob to go on attacker site `B` which send tens of request per second. It could result in getting Bob's ip banned from this REST API or preventing him to use the REST API correctly. I agree that's a bit farfetched but not totally impossible. – Xavier59 Aug 03 '17 at 19:48
  • 1
    @Xavier59 That is somewhat the equivalent of trying to DDoS a website by getting an img tag with the website as its source attribute on a high-traffic website. It isn't necessarily far-fetched. That being said, I don't see why CSRF tokens would do anything to mitigate such an attack. – Conor Mancone Aug 03 '17 at 20:11
  • Thanks @JesseKeilson. I'll have to digest that one. Just because an attack vector is secure doesn't mean its not dangerous! – Conor Mancone Aug 03 '17 at 20:12
  • @ConorMancone CSRF would mitigiate this issue by not allowing (and counting) request with a csrf token not associated with the right ip. Thus, Bob ip would not be blacklisted from using the rest api. Hope you get my point. – Xavier59 Aug 03 '17 at 20:31
  • @JesseKeilson The link in question was focused on CSRF attacks against OAUTH validation servers. It was an interesting read. The overall summary is something I learned before: in terms of a general work flow, OAuth2 is surprisingly insecure. To be clear I'm referring specifically to the process of issuing OAuth2 tokens. Using those tokens is a different matter, and is generally much more straight-forward. – Conor Mancone Aug 03 '17 at 21:00

7 Answers7

264

I wasn't originally aiming for a self-answer, but after more reading I've come up with what I believe to be a comprehensive answer that also explains why some might still be interested in CSRF protection on REST endpoints.

No cookies = No CSRF

It really is that simple. Browsers send cookies along with all requests. CSRF attacks depend upon this behavior. If you do not use cookies, and don't rely on cookies for authentication, then there is absolutely no room for CSRF attacks, and no reason to put in CSRF protection. If you have cookies, especially if you use them for authentication, then you need CSRF protection. If all you want to know is "Do I need CSRF protection for my API endpoint?" you can stop right here and leave with your answer. Otherwise, the devil is in the details.

h/t to paj28: While cookies are the primary attack vector for CSRF attacks, you are also vulnerable if you use HTTP/Basic authentication. More generally, if the browser is able automatically pass along login credentials for your app, then CSRF matters. In my experience cookies are the most common technology being exploited to make CSRF happen, but there are some other authentication methods that are used which can result in the same vulnerability.

REST = Stateless

If you ask someone "what is REST" you will get variety of answers that discuss a variety of different properties. You can see as much because someone asked that question on stack overflow: https://stackoverflow.com/questions/671118/what-exactly-is-restful-programming

One property of REST that I have always relied upon is that it is stateless. The application itself has state of course. If you can't store data in a database somewhere, your application is going to be pretty limited. In this case though, stateless has a very specific and important meaning: REST applications don't track state for the client-side application. If you are using sessions, then you are (almost certainly) keeping track of client-side state, and you are not a REST-full application. So an application that uses sessions (especially for logins) that are tracked via cookies is not a REST-full application (IMO), and is certainly vulnerable to CSRF attacks, even if it otherwise looks like a REST application.

I think it is worth a quick note that one reason that client-side statelessness is important for REST applications is that the ability of intermediaries to cache responses is also a desirable part of the REST paradigm. As long as the application is tracking client-side state, caching is not possible.

Rest ≠ Cookieless

For these reasons, I initially assumed that a fully-compliant REST application would never need sessions, never need cookies, and therefore never need CSRF security. However, there is at least one use-case that may prefer cookies anyway: persistent logins.

Consider a typical client-side (in this case browser, not mobile) web application. You get started by logging in, which uses a REST API to validate user credentials and in return is given a token to authorize future requests. For single page applications, you can just keep that token in memory, but doing so will effectively log the user out if they close the page. As a result, it would be good to persist the state somewhere that can last longer than a single browser session. Local storage is an option, but is also vulnerable to XSS attacks: a successful XSS attack can result in the attacker grabbing your login tokens and sending them off to the attacker to be used at their discretion.

For this reason, I have seen some suggest using cookies to store login tokens. With a cookie you can set the http-only flag, which prevents the application from reading the cookie after it is set. As a result, in the event of an XSS attack, the attacker can still make calls on your behalf, but they can't walk away with the authorization token all together. This use of cookies doesn't directly violate the statelessness requirement of REST because the server still isn't tracking client-side state. It is just looking for authentication credentials in a cookie, rather than the header.

I mention this because it is potentially a legitimate reason to use cookies with a REST API, although it is obviously up to a given application to balance the various security and usability concerns. I would personally try to avoid using cookies with REST APIs, but there may very well be reasons to use them anyway. Either way, the overall answer is simple: if you are using cookies (or other authentication methods that the browser can do automatically) then you need CSRF protection. If you aren't using cookies then you don't.

Conor Mancone
  • 29,899
  • 13
  • 91
  • 96
  • 9
    You're pretty much spot on. HTTP basic authentication can be vulnerable to CSRF as can IP-based auth and others. Conversely, Cookies can be safe if it's only ever a bespoke client that consumes the service, not a browser. That probably doesn't affect your decisions, but is worth bearing in mind. I've found people trying to define what is "proper REST" to be one of the least constructive discussions in IT. In practical terms, most services need authentication, and sessions are a reasonable way to do it. – paj28 Aug 07 '17 at 17:48
  • Thanks @paj28. HTTP basic authentication is a great point to mention. It's a lot less common, I think (which is why I forgot to mention it), but it is good to mention the exceptions when you are trying to come up with a comprehensive answer. – Conor Mancone Aug 07 '17 at 17:59
  • I didn't get your third point, Do I still need csrf protection if I store token in a session cookie? – Rathma Dec 20 '17 at 08:47
  • @HFA If you use cookies, especially for authentication, then you need CSRF protection. It doesn't matter what you are storing in the cookie: if the contents of a cookie are used to authenticate your users with your app, then CSRF is necessary because the browser automatically attaches cookies to all requests to your site. – Conor Mancone Dec 20 '17 at 12:58
  • I store authentication token inside a cookie with session life time in and use that cookie's content to intercept every http request and add an authorization header to http requests, does that count too? ;) – Rathma Dec 20 '17 at 13:01
  • @HFA: To use the content of that cookie you'd need to make the cookie NOT HttpOnly (i.e. accessible by JS). By doing that you're potentially exposing yourself to XSS, the same as if you were using Local Storage. Additionally, if your server _does_ accept the cookie as means of authenticating, then you're also open for CSRF. So just use Local Storage, and make sure to prevent XSS, cookies only make sense if your server is accepting them. – Boris B. Jan 15 '18 at 10:16
  • @BorisB. LocalStorage does not have session life time capability, so I use a session cookie set by javascript in user machine to store the token. I use an authorization header for authentication not cookie. – Rathma Jan 22 '18 at 10:36
  • HTTP is actually a stateless protocol. Why it's called that is because 2 different requests (connections) to the server can come from different places, but if the request content is the same, you would get pretty much the same data (if server state didn't change). That's why HTTP is a great protocol for REST. HTTP Cookies are also sent in the header (browser automatically adds it), while most REST APIs expect it in another header like Authorization. Whether you store your token in cookies, localStorage or sessionStorage, an XSS script will have access to it, but not a simple CSRF attack. – andho Feb 17 '19 at 20:30
  • I am using localStorage to save accesstoken, is this is vulnerable to CSRF? – Shashidhara Jun 18 '19 at 11:57
  • @Shashidhara nope. but it is now a higher XSS risk than an httpOnly cookie would have been (it's a tradeoff, not saying localStorage is bad, just different threat model) – Eran Medan Jul 16 '19 at 22:25
  • 3
    One small clarification: "No cookies = No CSRF" - I thought so too, but with Kerberos/NTLM native browser support, (SPNEGO) a kerberos token is being sent out to a set of whitelisted domains. These cases should also have CSRF protection as it's essentially the same as a cookie in the way that "something that is automatically sending something out on requests" so I think if you submit a form with target being a kerberized API endpoint, while you are in the internal network, there is a CSRF risk here too, no? – Eran Medan Jul 16 '19 at 22:28
  • Yep, even according to OWASP, it's not just cookies, if you have NTLM/Kerberos, CSRF is needed too. https://www.owasp.org/index.php/Top_10_2007-Cross_Site_Request_Forgery – Eran Medan Jul 16 '19 at 22:38
  • 2
    Another one about "No cookies = No CSRF" - if you store session token in the URL (bad idea, but happens), then it's as easy to trick user into form submission as with session token in cookies. This would require getting to know token in advance (browser history / proxy logs / server logs) which is an obstacle, but is doable under certain circumstances. Very specific case, but I thought it's worth to mention. – adamczi Mar 16 '20 at 09:42
  • The local storage being "vulnerable" to XSS is slightly niche. There is very little you can do in the event of a successful XSS attack. Sure, you can't leak cookies, but they can very much still do anything the user is privileged to do in their current session. In some situations, this is less free than if you had grabbed their token as they can only impersonate the user for a short time. But in many, it is actually more free as they don't have to deal with things like being flagged as a new machine and having to login again. – Ben May 28 '21 at 18:13
  • @Ben Indeed. On average I'd rather have an HTTP-only cookie, but the details depend on the use-case and, regardless, XSS really just means that you're screwed. – Conor Mancone May 29 '21 at 10:35
  • 1
    I'd like to expand a bit on something @paj28 alluded to. CSRF can be a problem when the server in question is relying on the client's network location for security. Either via an actual network separation (server only available on VPN, eg) or by explicitly looking at the source IP as part of its logic. In this case the attacker isn't taking advantage of secrets stored in the browser, but of the browser's "location". Chrome has some partial mitigations here (https://wicg.github.io/private-network-access/) but other browsers don't. – David Glasser May 17 '22 at 00:07
12

"there is no way for a browser to automatically provide authentication credentials even if it is somehow tricked into visiting the API endpoint"

Just be careful on private networks using integrated windows/kerberos authentication. In this scenario the brower will automatcially provide credentials (kerberos or NTLM token) if configured to do so.

So - I believe in this case CSRF is required.

stuartm9999
  • 121
  • 1
  • 2
  • 1
    Yep. https://www.owasp.org/index.php/Top_10_2007-Cross_Site_Request_Forgery "Authorizes requests based only on credentials that are automatically submitted such as the session cookie if currently logged into the application, or “Remember me” functionality if not logged into the application, **or a Kerberos token** if part of an Intranet participating in integrated logon with Active Directory is at risk." – Eran Medan Jul 16 '19 at 22:39
11

Whether or not CSRF protection is needed is based on 2 factors: -

Is the request doing a state changing action (not the same as REST API Statelessness) - State changing actions are any action that will change the state of the application.. for example delete something, add something, update something. These are actions using which the application will change the backed state of the user. All Post requests and a few Get requests will come under this category. REST APIs can have state changing actions.

Is the authentication provided by browser (not limited to cookies) - CSRF happens because authentication information is included in the request by browser irrespective of whether the request was started by the user, or some other open tab. So any kind of authentication in which browser can self include information needs CSRF protection. That includes both cookie based sessions and basic authentication.

For all requests that fall in above 2 categories CSRF protection is needed.

an0904
  • 173
  • 1
  • 2
  • 6
5

One thing I would add to the other answers is that CSRF protection is necessary only in the domain and path of the cookie in question. Or put another way:

Authorization != Authentication
Cookies == Authentication
Token == Authorization

This is relevant to the implementation of persistent logins (your 3rd point). If you affix your cookies to login.example.com, which hosts your login UI and your /authorize endpoint, then you can run an implicit OAuth flow every few minutes without requiring a new login (e.g. no password dialog). The client can go ahead and send the access token thus acquired to api.example.com without CSRF, as no cookies will be sent to that host.

So, you can still safely avoid dealing with CSRF on your REST APIs. But your login / authentication server better be bullet-proof (and CSRF protected).

Conor Mancone
  • 29,899
  • 13
  • 91
  • 96
Charlie Reitzel
  • 151
  • 1
  • 3
4

Rest API endpoints have a very important difference from other requests: they are specifically stateless, and should never accept/use data from either a cookie or session.

If that is how you define "REST API", then no CSRF is possible. CSRF, also called "session riding" [citation], obviously won't work if there is no session to "ride."

John Wu
  • 9,101
  • 1
  • 28
  • 39
  • 1
    If you disagree with part of my statement I would be happy to hear it. IMO, statelessness is a central goal of REST APIs. Sessions definitely make an API stateful. Cookies... technically I suppose you could use cookies and not be storing state server side, depending on how you use them. – Conor Mancone Aug 03 '17 at 20:44
  • 1
    Well I'd rather answer the question than quibble over terminology. But the S in HATEOS and the S in REST both stand for state. As long as client state isn't held on the server I don't think you've "violated" the spirit of the REST approach. – John Wu Aug 07 '17 at 16:13
  • I absolutely agree with you. It wasn't my desire to quibble over terminology. Part of the problem is that I wasn't clear enough in my original question: I was specifically talking about client state, not application state. – Conor Mancone Aug 07 '17 at 17:40
  • Yes State Transfer, that's the important point. The state isn't stored on the server side. The client tells the server about his state. And CSRF makes only sense if the api is accessible through regular web browsers. Some http methods like DELETE, PUT/PATCH are not even supported by todays browsers which makes the api only accessible to stand-alone http clients. – Sebi2020 Sep 13 '18 at 01:54
3

Answer : If you store the token in the localStorage and append it to your requests with JS, it would automatically guarantee CSRF protection (by the nature of the attack)

Addendum : As of whether it is more safe to use http-only cookies rather than localStorage (making it seem like this way of having CSRF protection would create a problem in case of XSS) : it is actually not. It would just make it a tiny bit harder for the attacker who is in control of JS on your site through an exploited XSS. @bobince have explained that with better words : Does setting httponly prevent stealing a session using XSS?

XSS is application level vulnerability, but its effects can be mitigated by limiting the power of the token through the usage of claims (restrict to minimum necessary)

Raywell
  • 31
  • 2
  • 2
    Welcome. As a Q&A site, we are different from a discussion site. Answers need to stand alone as an answer to the question and not a comment on another answer. – schroeder Feb 07 '20 at 10:01
  • @schroeder Thanks. Long time lurker first time poster, originally I wanted to comment but that required minimum reputation. However that comment lead to my original answer to the OP question in my last sentence : "should i use csrf protection" => No if the token is stored and appended to the header by JS – Raywell Feb 07 '20 at 10:08
  • All I can say is: keep contributing to the site to gain enough rep to unlock the ability to comment. You've made the first step in coming out of the "lurk". Keep going :) – schroeder Feb 07 '20 at 10:09
  • I'd recommend that you remove the comment to the other answer and make sure this answer directly addresses the question. – schroeder Feb 07 '20 at 10:12
  • I can, but I think it's quite important because it makes all the difference (reasoning leading to the answer). I will clarify the conclusion – Raywell Feb 07 '20 at 10:14
  • I have reworded the answer, hope it looks less as a discussion (the contents are pretty much the same). I'm waiting for my reputation to comment on the misleading part in the accepted answer. In the meanwhile I'm enjoying my autogenerated swastika profile image – Raywell Feb 07 '20 at 10:35
2

There's a small specific caveat to existing answers that I'd like to add. While Conor is right that cookies are the only form of locally stored authentication data sent along all requests, they're not the only form of locally stored authentication data used by websites. What this means is, if a site decides to keep their JWTs/Session tokens in something like LocalStorage or SessionStorage, these can still sometimes be automatically pulled out via javascript and then used without user interaction. That means it is sometimes still possible to perform CSRF attacks "once removed" by redirecting a user to a domain-matching frontend URI that then sends the creds along. This can be accomplished in a more direct way if you have reflected XSS, but there are cases where this is unnecessary and such pages+scripts already exist.

In these cases, the problem isn't the lack of CSRF tokens on the REST API; it's the lack of tokens on the endpoints of whatever frontend is interacting with it.

  • Wow, that is genial! So trivial, if a JS could be somehow injected into the target site, any session can be stolen. – peterh Aug 13 '20 at 06:31
  • @peterh-ReinstateMonica Cute, but as I said in the post that's not what I meant. It's not uncommon you have a frontend sitting in front of the rest API with some endpoints that already perform mutative actions upon load, without requiring you to inject code into them. – Dean Valentine Aug 13 '20 at 07:02