Should I use CSRF protection on Rest API endpoints?
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.
"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.
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.