I am looking to build a web application using API-Centric architecture.
The frontend of the application would make requests to the REST API using AJAX.
The API is also used by other clients for various purposes. I'm of the opinion that the use of CSRF tokens may not be applicable to their implementation.
Other approaches include verifying the origin in the headers, but of course, headers can easily be spoofed.
How could I implement a robust CSRF prevention strategy for this application?
Some proposition: First You can use api-url like GET api/gime-csrf which return CSRF token as response and also set it in http-only cookie (so JS has no access to it - but remember to block TRACE request in server to prevent XST attack). Then when you make some "save state" request like POST/PUT/PATCH - you just put CSRF in some request header - and in server you compare header token value with cookie token value.
Related
Recently I'm studying some basics of Web security and there is something I couldn't understand.
How do anti-CSRF tokens work in SPA-API communications?
As far as I understand, anti-CSRF is used in SPA-API communications as followings;
The browser sends a login request to the API.
The API servers generates a token and sends it back to the browser.
The browser stores it, and when the browser makes the next request, token with be sent together.
The API can make sure that the request came from the genuine front-end because it contains the token.
A question pops up in my mind--how can it prevent CSRF?
If the token is stored in cookie, it will automatically be sent to API whenever a request happens, like usual session cookies. And even if it's stored in other storage(like session storage or local storage), it can be accessed using JavaScript.
So once users are attracted to the attacker's site, anti-CSRF tokens are completely useless.
On the top of that, I can't understand what's the difference between anti-CSRF token and usual cookies used in authentication/authorization……
Maybe I've made a terrible misunderstanding about how anti-CSRF tokes work. Please put a finger on what's wrong about it.
One of the most common CSRF vulnerabilities exists when an attacker can submit a request to an endpoint using an authenticated user's cookies. If you're not using cookies (i.e., to authenticate a user's request) or some other automatic authentication technique (like HTTP Basic Authentication), then there's generally no need for CSRF tokens.
Example #1:
Let's say you're using a REST API that depends on an access token or bearer token for authentication. This token is usually submitted in the HTTP Authorization header (not a cookie). In this case, as long as authentication isn't automatic (e.g., using a cookie), then there's no need for a CSRF token.
Example #2:
In this case, let's say the browser does send a session cookie to a web service/API to authenticate the request. Then, yes, you would be vulnerable to CSRF if anti-CSRF controls aren't implemented. One way to prevent this is to provide an anti-CSRF token to the browser when the SPA is loaded. The browser can then send that token with the request to the endpoint. The web service will then have to validate that token when the request is received.
There are a number of ways that this validation can occur. This could be done using double-submit cookies, a cookie-to-header token, cryptographic techniques, or even a shared database.
Using Anti-CSRF Tokens:
Anti-CSRF tokens generally should not be stored in cookies. As stated in the OWASP CSRF Prevention Cheat Sheet:
A CSRF token can be included in the <meta> tag. All subsequent calls
in the page can extract the CSRF token from this <meta> tag. It can
also be stored in a JavaScript variable or anywhere on the DOM.
However, it is not recommended to store it in cookies or browser local
storage.
For example, an anti-CSRF token might get embedded in the page as:
<meta name="csrf-token" content="{{ csrf_token() }}">
Where the csrf_token() calls some server-side function that embeds the token in the tag.
It can then be read in JavaScript using:
let csrf_token = document.querySelector("meta[name='csrf-token']").getAttribute("content");
And then transmitted to the server when an API request is made (e.g., in a X-CSRF-Token header in a POST request). In addition, the token should be unique to the session.
However, even if a token were to be stored in a cookie, the cookie could be set with the HttpOnly header. This prevents the cookie from being read by JavaScript. This is more so useful in mitigating cross-site scripting (XSS) attacks.
Additional Info:
This StackExchange Security question includes a lot of good info on using CSRF protection in REST APIs.
Other good resources about CSRF in general:
https://portswigger.net/web-security/csrf
https://owasp.org/www-community/attacks/csrf
Consider I'm creating a RESTful API (like Twitter API) and I need only a single key token to access the endpoint GET /messages.
The token needs to be sent via header access_token for example.
If I don't pass the token I'll get an 4xx error.
In the RESTful API scenario, is this all needed to protect against CSRF attacks? I mean, in RESTful APIs I'm not using Cookies to manager a user session, since the idea here is to not be a session (Stateless is one of the principles of REST).
Am I forgetting something or is this correct? I don't see why I would need a anti CSRF token besides my access token.
Thanks in advance!
Short answer: if your access_token is not a cookie, yes, it's enough to protect you against CSRF.
Long answer:
A CSRF attack can only happen when HTTP client automatically sends some authentication data(usually cookies) to server. The key point is attacker do not need to know the Cookie, it's is automatically sent if web user accesses 2 sites(your site and the attacker's site) using the same browser.
To anti CSRF, server sends to client a private token that browser does not automatically send it to server(so it's must not be a cookie). The developer has to write code to attach the token to each subsequent request.
CSRF is an issue for using Cookie by Web browser, if you are developing restful API that is not used by web browser, usually, you do not need to care about CSRF
#Bart Firstly CSRF attacks are usually from a trusted user. Which means that the client has successfully authenticated himself by maybe passing a valid token in case of a rest API. The attack could be by passing let's say a javascript which can change the state of a resource. So just having a single key token won't really help to avoid CSRF attacks.
Please refer to below URL for more reference on CSRF :-
https://en.wikipedia.org/wiki/Cross-site_request_forgery
Most of the frameworks like Spring have inbuilt support for CSRF.
I don't know much about CSRF, but after reading the doc, it seems it only happens in browser. So now I have a library with rest api, but no ui. Do I need to take care of CSRF in this rest api ? Thanks
First of all, it's important to note that CSRF is an attack that can be exploited in browers.
According to Guidelines for Implementation of REST, a document issued by NSA, REST APIs are vulnerable to CSRF attacks:
F. Cross Site Request Forgery:
Cross site request forgery (CSRF) attacks attempt to force an authenticated user to
execute functionality without their knowledge. [...]
It is important to note that CSRF attacks execute functionality, but are unable to
interact with the response from the targeted server. [...]
REST is stateless at its core and thus inherently vulnerable to CSRF attacks. [...]
Two approaches are suggested to ensure protection. Summarizing them below:
Custom HTTP header
The first method involves checking the presence of a custom header (agreed-upon between the server and a client – e.g. X-CSRF or X-Requested-By) in all state-changing requests coming from the client. The value of the header does not really matter. It works, because the browser would not send custom headers unless the web page makes a request using XMLHttpRequest, which only allows requests to the same site.
This method is currently used by Jersey, the JAX-RS reference implementation for REST web services in Java.
And it's also mentioned in Robust Defenses for Cross-Site Request Forgery from Stanford University.
CSRF tokens
The second method involves protecting REST endpoints against CSRF attacks by establishing session state. This approach violates REST principles and involves the use of a CSRF token that is generated for each action, then associated with the user session and submitted with each important website action.
This essentially forces a sequential ordering of actions on the application.
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).
Folks,
What is a simplest way to track consumer applications accessing RESTful API services inside department.
We do not restrict access - no authentication/authorization - open for invocation, trusted environment.
No tools like OAuth AuthZ servers or API management yet... but might be heading there at some point.
For now we thought to request consumers just to include some custom HTTP Header like X-Client-Id and log it on the server side for stats etc..
But knowing that in the future we might want to switch to more standard ways of doing things ... what would be best alternative to have to change less code in the future ?
Have the "clientId" in the Authorization: OAuth token (like access token)
Have JWT token in the Authorization header (looks too much - signing,base 64 etc for simple client id tracking ...)
Any ideas would be appreciated
We recently implemented this for one of our REST platforms and we used a combination of BOTH the points you mentioned, meaning Authorization header & JWT token. Although, JWT is ONLY for authentication and GETTING an access_token (oauth token) which is later used with calling actual resource apis. I will discuss how we handled this situation and you can decide on how you want to implement it.
1) Authentication
Client sends a JWT to your authentication service (/api/oauth2/auth). (If you want more reading on JWT, you can read here and here of how JWT is implemented by google and how you can use spring-security-jwt libary to handle all the signing and encrypting/decrypting). You get the "clientId" out of JWT after decrypting and verifying the signature and after server does all the authentication, you respond back with a 'refresh_token' and an 'access_token'. Server will save the access_token as well and map it to the clientId so that when client makes requests using access_token, you can know which client is making the request. The access_token expires in some time (ideally in an hour) and when it expires, the client uses the 'refresh_token' to get a new access token by posting refresh_token to some refresh token url (/api/oauth2/auth/token)
2) Authorization
Client takes the 'access_token' and uses the access token to make all the subsequent requests on all other apis (/api/*). Ideally, the access_token is sent as a part of the "Authorization" header. Server uses request filters (if you are using JAX-RS, you can use something like ContainerFilterRequest to add filters to specific url patterns and intercept them) to filter EACH request and parse out the Authorization header value. You will get the access_token from the header and from the access_token you can get the clientId that you mapped in step 1). You can do other authorization logic in the security filter and if everything goes through, you can use this information to LOG that clientId and the request that the client made.
This way you can kill 2 birds with one stone : Implement a security layer & log the information about customers (what calls they are making, how many time etc. etc.). In case you don't want to implement security filter just yet (as you mentioned it might be in the future), for now, the clients can just pass on the "clientId" (base64encoded or not, upto you) as a part of "Authorization" header. If all the calls are from a "trusted" network, it should be ok, although not as secure. This way, when you ACTUALLY implement a JWT and Oauth based security layer, all you have to do is change your ContainerFilterRequest logic to parse out access_token instead of client id (as mentioned in step # 2).
I hope this helps ! For more information on security filters you can have a look at this answer: Basic Authentication of a resource in Dropwizard. It says dropwizard, but it mostly talks about JAX-RS.
To implement full AuthN/AuthZ layer for consumer tracking would be an overkill for now.
We thought to use either to Authorzation header to pass custom client_id token:
Authorization: Custom <Client_Id>
or to use some limited version of JWT (no signatures as there no intent to validate them)
as access token
Authorization: JWT <JWT>
Where JWT could be:
{"alg":"none","typ":"JWT"}
{
"iss":"Client_ID",
"aud": REST Service URI,
"iat":1328550785
}
I do not see description of access_token format in the specification https://datatracker.ietf.org/doc/html/rfc6749#section-1.4
Are there any contraints to use JWT as access token?