Is it possible to protect stateless REST API from both XSS and CSRF attacks?
Currently, I'm using JWT token stored in secure/httpOnly cookie for stateless authentication. This should protect the API from most common XSS attack: stealing cookies with XSS-injected JavaScript and sending them to the attacker.
However, this doesn't protect the API from CSRF attack, where attacker would trick the authenticated user to follow a link to the particular web API call to actuate adverse transaction on behalf of the victim. How could I protect the API from this attack without introducing server side state?
Also, is it true XSS vulnerability would inheritedly allow CSRF type attack in the following scenario: Injected JavaScript would retrieve CSRF token from the client side state, DOM or the browser storage and prepare a malicious ajax call to the server. Browser would still automatically include the httpOnly cookie for the same origin request. Is there a way to get protected from this other than protecting from the XSS vulnerability in the first place?
Stateless anti-forgery tokens
The first question is about preventing CSRF without server-side state. The current approach for stateless anti-forgery tokens is the double submit cookie pattern.
CSRF attacks depend on the browser automatically sending the API's own cookies back to it, regardless of where the request originated. The attacker doesn't have or need access to the cookie contents. They only need to trick the user into loading malicious HTML. The double cookie pattern adds a new requirement: the attacker must know and separately send the contents of the anti-forgery cookie.
There are ways for an attacker to overwrite the anti-forgery cookie with their own. So you may want to look at some additional security hardening for this approach. Especially HMAC signing the anti-forgery token to prevent token substitution. Using HSTS and the __Host cookie prefix to ensure transport security and proper cookie scope. And having the client provide the anti-forgery token in a custom header.
The custom header ensures the request must be sent from JS, since HTML-tag-based CSRF attacks cannot set custom headers. Being sent from JS also triggers additional protections. For cross-origin requests it triggers SOP on the browser and CORS validation on the server. The server can also do basic Origin validation.
Regarding the scope of CSRF attacks, here is a note from the OWASP CSRF link at the top.
Forcing the victim to retrieve data doesn’t benefit an attacker because the attacker doesn’t receive the response, the victim does. As such, CSRF attacks target state-changing requests.
XSS question
Yes, an XSS attack could happen that way. Once a malicious script is loaded into JS, it has free reign to use anything accessible to Javascript. Including app code/memory, browser storage, and cookies. Even though HttpOnly cookies are not readable, they can still be sent in requests. A non-targeted attack might look for key data in locations used by popular frameworks. And might try to probe for popular/discoverable API frameworks on the server. A targeted attack means the attacker studied your system and crafted a custom payload for it.
The primary vector for XSS is unsanitized external data (user input, database values, etc.). To prevent XSS, check out these guidelines from OWASP. Of note is that front-end frameworks like Angular, React, Svelte, Vue, and others have built-in XSS protection. Because they sanitize data before rendering it. Example: an attacker enters an HTML string into an input. When it is later displayed, these frameworks HTML-encode the string. So left and right angle brackets are replaced with < and > and so on. This causes the browser to evaluate the string as text instead of runnable HTML. But you can still mess it up in different ways if careless.
XSS attacks can also come from external resources. Maybe a compromised CDN or NPM script. If your deployed code takes dependencies on NPM libraries, pay extra attention to NPM audit warnings. One attack pattern is to attach a small loader (easier to go unnoticed), which will fetch attack payloads at runtime. A CSP policy can help prevent this. Specify an allowed list of resources -- your app assets and API URLs -- and block all others. CSP can also prevent data exfiltration.
For both CSRF and XSS
For attacks on your API, you can additionally employ server-side mitigations. IP-based throttling / temporary bans, unusual activity grey-listing and alerting, etc.
For especially sensitive operations, one strategy is to use an escalated authorization. This could take the form of requiring the user to re-authenticate or use a 2nd factor like a one-time password. This can block automated attacks since it requires active user intervention.
To mitigate attackers using existing escalated authorizations (which may also be in a cookie or app memory), they can have short expirations and be limited to specific operations. To go even further, the approved operations + relevant data can be signed. This will prevent malicious scripts from reusing an escalation to execute the same kind of operation with different data. Even further, these sensitive operations can be idempotent. So if an attacker does resend already-executed operations, they will not cause any additional changes in the system.
Zooming out
Try to engineer your systems to be as uninteresting as possible to hackers. Use trusted external services for sensitive needs like credit cards and credentials. Ideally (from a security perspective) the hacking risk would be reduced to just data vandalism/loss. So in the worst case that a breach happens, it would have little long-term impact. And it could be recovered with common practices, including routinely tested backups. And then further mitigations added for the specific attacks used.
Tread especially carefully with user-to-user interaction. Since this adds more targets and pivot points for hackers -- your user base. The most security-conscious eyes should be on these pieces. Not only for technical dangers like user-to-user XSS attacks, but also social ones. Human weaknesses are the most well-known and easiest to exploit.
Lastly, there is no sense investing in mitigations which have low risk/consequences in your situation. So do not take everything here as a requirements checklist. It's not a complete list anyway. Focus on your biggest risks first. Reevaluate periodically.
You can generate a token (e.g. a UUID) and put it into the jwt token as well as send it back to the client. Then the client sends it during every each request in a header. Then the server can compare the token in the header and the token in the jwt token to make sure the request comes from the client who was aunthenticated.
Is using sessions in a RESTful API really violating RESTfulness? I have seen many opinions going either direction, but I'm not convinced that sessions are RESTless. From my point of view:
authentication is not prohibited for RESTfulness (otherwise there'd be little use in RESTful services)
authentication is done by sending an authentication token in the request, usually the header
this authentication token needs to be obtained somehow and may be revoked, in which case it needs to be renewed
the authentication token needs to be validated by the server (otherwise it wouldn't be authentication)
So how do sessions violate this?
client-side, sessions are realized using cookies
cookies are simply an extra HTTP header
a session cookie can be obtained and revoked at any time
session cookies can have an infinite life time if need be
the session id (authentication token) is validated server-side
As such, to the client, a session cookie is exactly the same as any other HTTP header based authentication mechanism, except that it uses the Cookie header instead of the Authorization or some other proprietary header. If there was no session attached to the cookie value server-side, why would that make a difference? The server side implementation does not need to concern the client as long as the server behaves RESTful. As such, cookies by themselves should not make an API RESTless, and sessions are simply cookies to the client.
Are my assumptions wrong? What makes session cookies RESTless?
First of all, REST is not a religion and should not be approached as such. While there are advantages to RESTful services, you should only follow the tenets of REST as far as they make sense for your application.
That said, authentication and client side state do not violate REST principles. While REST requires that state transitions be stateless, this is referring to the server itself. At the heart, all of REST is about documents. The idea behind statelessness is that the SERVER is stateless, not the clients. Any client issuing an identical request (same headers, cookies, URI, etc) should be taken to the same place in the application. If the website stored the current location of the user and managed navigation by updating this server side navigation variable, then REST would be violated. Another client with identical request information would be taken to a different location depending on the server-side state.
Google's web services are a fantastic example of a RESTful system. They require an authentication header with the user's authentication key to be passed upon every request. This does violate REST principles slightly, because the server is tracking the state of the authentication key. The state of this key must be maintained and it has some sort of expiration date/time after which it no longer grants access. However, as I mentioned at the top of my post, sacrifices must be made to allow an application to actually work. That said, authentication tokens must be stored in a way that allows all possible clients to continue granting access during their valid times. If one server is managing the state of the authentication key to the point that another load balanced server cannot take over fulfilling requests based on that key, you have started to really violate the principles of REST. Google's services ensure that, at any time, you can take an authentication token you were using on your phone against load balance server A and hit load balance server B from your desktop and still have access to the system and be directed to the same resources if the requests were identical.
What it all boils down to is that you need to make sure your authentication tokens are validated against a backing store of some sort (database, cache, whatever) to ensure that you preserve as many of the REST properties as possible.
I hope all of that made sense. You should also check out the Constraints section of the wikipedia article on Representational State Transfer if you haven't already. It is particularly enlightening with regard to what the tenets of REST are actually arguing for and why.
First, let's define some terms:
RESTful:
One can characterise applications conforming to the REST constraints
described in this section as "RESTful".[15] If a service violates any
of the required constraints, it cannot be considered RESTful.
according to wikipedia.
stateless constraint:
We next add a constraint to the client-server interaction:
communication must be stateless in nature, as in the
client-stateless-server (CSS) style of Section 3.4.3 (Figure 5-3),
such that each request from client to server must contain all of the
information necessary to understand the request, and cannot take
advantage of any stored context on the server. Session state is
therefore kept entirely on the client.
according to the Fielding dissertation.
So server side sessions violate the stateless constraint of REST, and so RESTfulness either.
As such, to the client, a session cookie is exactly the same as any
other HTTP header based authentication mechanism, except that it uses
the Cookie header instead of the Authorization or some other
proprietary header.
By session cookies you store the client state on the server and so your request has a context. Let's try to add a load balancer and another service instance to your system. In this case you have to share the sessions between the service instances. It is hard to maintain and extend such a system, so it scales badly...
In my opinion there is nothing wrong with cookies. The cookie technology is a client side storing mechanism in where the stored data is attached automatically to cookie headers by every request. I don't know of a REST constraint which has problem with that kind of technology. So there is no problem with the technology itself, the problem is with its usage. Fielding wrote a sub-section about why he thinks HTTP cookies are bad.
From my point of view:
authentication is not prohibited for RESTfulness (otherwise there'd be little use in RESTful services)
authentication is done by sending an authentication token in the request, usually the header
this authentication token needs to be obtained somehow and may be revoked, in which case it needs to be renewed
the authentication token needs to be validated by the server (otherwise it wouldn't be authentication)
Your point of view was pretty solid. The only problem was with the concept of creating authentication token on the server. You don't need that part. What you need is storing username and password on the client and send it with every request. You don't need more to do this than HTTP basic auth and an encrypted connection:
Figure 1. - Stateless authentication by trusted clients
You probably need an in-memory auth cache on server side to make things faster, since you have to authenticate every request.
Now this works pretty well by trusted clients written by you, but what about 3rd party clients? They cannot have the username and password and all the permissions of the users. So you have to store separately what permissions a 3rd party client can have by a specific user. So the client developers can register they 3rd party clients, and get an unique API key and the users can allow 3rd party clients to access some part of their permissions. Like reading the name and email address, or listing their friends, etc... After allowing a 3rd party client the server will generate an access token. These access token can be used by the 3rd party client to access the permissions granted by the user, like so:
Figure 2. - Stateless authentication by 3rd party clients
So the 3rd party client can get the access token from a trusted client (or directly from the user). After that it can send a valid request with the API key and access token. This is the most basic 3rd party auth mechanism. You can read more about the implementation details in the documentation of every 3rd party auth system, e.g. OAuth. Of course this can be more complex and more secure, for example you can sign the details of every single request on server side and send the signature along with the request, and so on... The actual solution depends on your application's need.
Cookies are not for authentication. Why reinvent a wheel? HTTP has well-designed authentication mechanisms. If we use cookies, we fall into using HTTP as a transport protocol only, thus we need to create our own signaling system, for example, to tell users that they supplied wrong authentication (using HTTP 401 would be incorrect as we probably wouldn't supply Www-Authenticate to a client, as HTTP specs require :) ). It should also be noted that Set-Cookie is only a recommendation for client. Its contents may be or may not be saved (for example, if cookies are disabled), while Authorization header is sent automatically on every request.
Another point is that, to obtain an authorization cookie, you'll probably want to supply your credentials somewhere first? If so, then wouldn't it be RESTless? Simple example:
You try GET /a without cookie
You get an authorization request somehow
You go and authorize somehow like POST /auth
You get Set-Cookie
You try GET /a with cookie. But does GET /a behave idempotently in this case?
To sum this up, I believe that if we access some resource and we need to authenticate, then we must authenticate on that same resource, not anywhere else.
Actually, RESTfulness only applies to RESOURCES, as indicated by a Universal Resource Identifier. So to even talk about things like headers, cookies, etc. in regards to REST is not really appropriate. REST can work over any protocol, even though it happens to be routinely done over HTTP.
The main determiner is this: if you send a REST call, which is a URI, then once the call makes it successfully to the server, does that URI return the same content, assuming no transitions have been performed (PUT, POST, DELETE)? This test would exclude errors or authentication requests being returned, because in that case, the request has not yet made it to the server, meaning the servlet or application that will return the document corresponding to the given URI.
Likewise, in the case of a POST or PUT, can you send a given URI/payload, and regardless of how many times you send the message, it will always update the same data, so that subsequent GETs will return a consistent result?
REST is about the application data, not about the low-level information required to get that data transferred about.
In the following blog post, Roy Fielding gave a nice summary of the whole REST idea:
http://groups.yahoo.com/neo/groups/rest-discuss/conversations/topics/5841
"A RESTful system progresses from one steady-state to the
next, and each such steady-state is both a potential start-state
and a potential end-state. I.e., a RESTful system is an unknown
number of components obeying a simple set of rules such that they
are always either at REST or transitioning from one RESTful
state to another RESTful state. Each state can be completely
understood by the representation(s) it contains and the set of
transitions that it provides, with the transitions limited to a
uniform set of actions to be understandable. The system may be
a complex state diagram, but each user agent is only able to see
one state at a time (the current steady-state) and thus each
state is simple and can be analyzed independently. A user, OTOH,
is able to create their own transitions at any time (e.g., enter
a URL, select a bookmark, open an editor, etc.)."
Going to the issue of authentication, whether it is accomplished through cookies or headers, as long as the information isn't part of the URI and POST payload, it really has nothing to do with REST at all. So, in regards to being stateless, we are talking about the application data only.
For example, as the user enters data into a GUI screen, the client is keeping track of what fields have been entered, which have not, any required fields that are missing etc. This is all CLIENT CONTEXT, and should not be sent or tracked by the server. What does get sent to the server is the complete set of fields that need to be modified in the IDENTIFIED resource (by the URI), such that a transition occurs in that resource from one RESTful state to another.
So, the client keeps track of what the user is doing, and only sends logically complete state transitions to the server.
As I understand, there are two types of state when we are talking about sessions
Client and Server Interaction State
Resource State
Stateless constraint here refers to the second type in Rest. Using cookies (or local storage) does not violate Rest since it is related to the first.
Fielding says: 'Each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client.'
The thing here is that every request to be fulfilled on the server needs the all necessary data from the client. Then this is considered as stateless. And again, we're not talking about cookies here, we're talking about resources.
HTTP transaction, basic access authentication, is not suitable for RBAC, because basic access authentication uses the encrypted username:password every time to identify, while what is needed in RBAC is the Role the user wants to use for a specific call.
RBAC does not validate permissions on username, but on roles.
You could tric around to concatenate like this: usernameRole:password, but this is bad practice, and it is also inefficient because when a user has more roles, the authentication engine would need to test all roles in concatenation, and that every call again. This would destroy one of the biggest technical advantages of RBAC, namely a very quick authorization-test.
So that problem cannot be solved using basic access authentication.
To solve this problem, session-maintaining is necessary, and that seems, according to some answers, in contradiction with REST.
That is what I like about the answer that REST should not be treated as a religion. In complex business cases, in healthcare, for example, RBAC is absolutely common and necessary. And it would be a pity if they would not be allowed to use REST because all REST-tools designers would treat REST as a religion.
For me there are not many ways to maintain a session over HTTP. One can use cookies, with a sessionId, or a header with a sessionId.
If someone has another idea I will be glad to hear it.
i think token must include all the needed information encoded inside it, which makes authentication by validating the token and decoding the info
https://www.oauth.com/oauth2-servers/access-tokens/self-encoded-access-tokens/
No, using sessions does not necessarily violate RESTfulness. If you adhere to the REST precepts and constraints, then using sessions - to maintain state - will simply be superfluous. After all, RESTfulness requires that the server not maintain state.
Sessions are not RESTless
Do you mean that REST service for http-use only or I got smth wrong? Cookie-based session must be used only for own(!) http-based services! (It could be a problem to work with cookie, e.g. from Mobile/Console/Desktop/etc.)
if you provide RESTful service for 3d party developers, never use cookie-based session, use tokens instead to avoid the problems with security.
Someone to explain please (hopefully with simple words for newbies) why a web application built upon a RESTful API can be CSRF exempt?
I received such assertion after asking: Serializing FormView data in JSON, but honnestly I can't figure out why?
Thanks in advance
CSRF or Cross Site Request Forgery, in layman terms, is meant to allow only selected sources(your own website) to submit data to particular url. It prevents misuse of your functionality by other websites or robots.
Say, I have an url for registration, /registration/, but I don't want to allow external submission of POST data to /registration/. So, I would provide a crsf cookie(depending on host and other stuff) when GET request is issued for /registration/, and ensure that same cookie is provided with POST request. This will ensure that users who have requested the registration form(i.e. genuine web users, not robots), would be able to register. It is not completely full-proof, but ensures some level of security.
Now, We don't use CSRF in API's due to following:-
Technically, CSRF is stored as cookie, since browser is not the intended client of API's, it is of no use.
Secondly, API's are supposed to use specialized client and user authentication, thereby eliminating the need for using any CSRF protection.
Thirdly, Restful api's are supposed to be stateless, therefore the order of API calls should not matter, which is essential for working of CSRF.
Note:-
If you have frontend framework like Angular or intend to use api's on browser too, then it is perfectly ok to use CSRF. In that case you are suppose to write two types of authentication for your apis.
Token Based Authentication - for non-browser clients
Session Authentication - for browser based clients (With csrf)
In this case, any request to api must authenticate with atleast one of the authentication.
According to owasp.org:
Cross-Site Request Forgery (CSRF) is a type of attack that occurs when a malicious Web site, email, blog, instant message, or program causes a user's Web browser to perform an unwanted action on a trusted site for which the user is currently authenticated.
This is not an issue for REST Web services because either:
1) you usually want your service to be accessible from multiple applications (Mobile app, browser, etc.)
2) you have to provide a direct authentication for each request, so this kind of attack is not applicable for REST services. The authentication is done by your application (let's say javascript) and no directly by your browser (sending the session id), so even if a malicious application redirect the user to your webpage, it cannot automatically trigger your javascript function to perform the request (and the authentication).
I need to add CSRF protection to a web application.
Problem is in the fact that the app relies heavily on links (GET requests that is) to make changes in the database.
Links are generated using a class, so I could easily add an extra parameter for CSRF token to each link.
However, I understand that CSRF token in a GET request might not be a good enough protection.
Note that app is only available over HTTPS, so GET params can not be exposed/stolen during client/server communication (but history stealing issue remains).
Could GET CSRF token param be considered "safe enough" in this setting?
If not, what is the best way to solve this problem? Only thing that comes to my mind is to wrap each of my links into a form (ether explicitly, or creating form onSubmit using JavaScript).
To be able to read the response to a CSRF attack’s request, an attacker would need to get the victim to execute his JavaScript code. So, CSRF for a "GET" request is almost not useful. This is assuming you have followed the standards that "GET" requests should not modify any data and any modifications need to be done only using "POST"
Using cookie based authentication and SSL should keep you away from a guy who is trying to change the parameters
You may want to introduce some signing based on timestamp to avoid replay attacks
That said, if you have any POST requests, you should consider the CSRF protection.