CSRF Prevention Without Modification to client - rest

I need to integrate CSRF Prevention in our existing REST Service.
We have created many rest resources and published its detail for other developers to consume. Anyone in the organization can use it. I have no control how he uses it, the form he uses or the httpclient. I have no idea who has used it till date and I cannot change all the clients. Hence, I cannot add a hidden text fields/tokens to the form, since I do not have access to the clients. Also, I cannot use the double authentication or captcha, because it wont work with the httpclient implementations. Is there any other way that I can prevent the misuse of the REST service against CSRF.

You could do this by checking the X-Requested-With header.
If any web clients are already using JQuery, then this header will be passed automatically and ensures that the request is not a cross-domain request either by AJAX or by HTML forms. This header will not be sent at all for HTML forms, so this will work if no web clients use HTML forms.
If your web clients use plain JavaScript then you could check that the Origin header is set to a valid domain. Please note that some versions of some browsers do not set this when the request is not cross domain.
The only drawback is that non-web clients would have to set one of these headers, or that you have some way of identifying these non-web clients from your REST service so that you could bypass the checks in these cases.
If you non-web clients already send any headers other than the following:-
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type
then you could verify the value is passed (instead of X-Requested-With or Origin) to ensure that this is not a CSRF attack as custom headers cannot be sent in a CSRF attack. Even the User-Agent could be used - this can be spoofed only by a HTTP client but not by an attacker inside a browser which is the only relevant place that a CSRF attack can happen.

Related

How to prevent CSRF in API-Centric Web Application

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.

CAS REST authentication API accepts text/* but not application/* content type

I have configured my CAS server to activate REST authentication, as per these instructions. However, in order for it to work, I must submit my credentials in plain text (content type text/html or xml) and not application/x-www-form-urlencoded as per the instructions. The credentials are lost when sent in the latter format.
I am uncomfortable sending my login credentials in plain text. Is this a bug in CAS and how can it be fixed? I am assuming it is less secure to send login credentials as text content type vs application, as the latter (I assume) does hash (or somehow else obfuscates) the content sent.
I should also mention that I had to make a fix to a bug in CAS due to which credentials were being lost regardless of the content type, by implementing this solution in my maven overlay. After that, only text-based content types worked and CAS does authenticate (albeit I find it annoying that the service returns HTML and not XML/JSON or even plain text, for the ease of programmatic processing).
RELATED: REST API endpoint /v1/tickets appears to lose credential request parameters
Content-type has no effect on the confidentiality of data in the request. Sending it with application/x-www-form-urlencoded in a request is not more (nor less) secure than text/html or text/xml if only confidentiality is considered. There is no additional security value in using any of those in a request, somebody having access to the raw request source (a MitM attacker) will see request contents either way. HTTPS effectively mitigates this risk with regard to MitM attackers on the network inbetween nodes, but not on endpoints where SSL is terminated (the source and target computers, and also any node inbetween that terminates SSL, like for example a company proxy with a trusted root certificate on clients - a fairly common setup).
As for the possible security benefit of using text/plain instead of application/x-www-form-urlencoded, please see my answer to your other question. In short, using text/plain may prevent some CSRF attacks.

How to send a password in a GET request to access a REST resource

I have a REST service that is already secured with basic authentication using the Authorization header. This is used to access the service in general and is required for any request. i.e. "User1", "password1".
I have a "file" resource which can have an additional password associated with it (i.e a password protected Word document, PDF, etc), "docpassword". What is the best way to send sensitive information like this? I'm especially interested in how to send the password for a GET request, but I'd like to have a universal solution that will also work for POST requests.
Maybe a custom header?
The HTTP protocol defines the standard Authorization header for sending authentication data (credentials) to the server. This header is defined in the RFC 7235 (which makes the old RFC 2616 obsolete and updates the RFC 2617):
4.2. Authorization
The Authorization header field allows a user agent to authenticate
itself with an origin server -- usually, but not necessarily, after
receiving a 401 (Unauthorized) response. Its value consists of
credentials containing the authentication information of the user
agent for the realm of the resource being requested.
Authorization = credentials
[...]
Please note that the name of this HTTP header is unfortunate because it carries authentication data instead of authorization. Anyways, this is the standard headers for sending credentials in the HTTP protocol.
Once you are already using the HTTP Basic Authentication Scheme to authenticate the users in your application, I believe you are already using the standard Authorization header.
I usually do not recommend custom headers, especially when the standard headers can be used instead, but your scenario seems not so common: You need to perform two authentications on the same request.
So, maybe a custom header such as X-Auth-Document or Document-Authentication with the document's password will be fine for GET requests. If you decide not using GET and decide using POST to access this resource, you can consider sending the document's password in the request paylod.
Anyways, don't forget using HTTPS: is highly advisable once you are sending sensitive data, such as credentials, over the wire. And HTTPS will protect you against the man-in-the-middle attack.
HTTP already has an authentication method, see for example this RFC: https://www.rfc-editor.org/rfc/rfc2617
Edit after clarification of question: There is nothing preventing the server to make additional challenges, even based on single resource basis. I must admit I did not implement such a thing yet, but each authorization can have its own realm. You could specify different realms, even down to document level if you really want to. The server then can potentially make multiple challenges in each realm (first login, then document). Remember, you can cache successful authentications, either on the client (for a realm, like a browser does), or giving out cookies with a cached token.
This would have the advantage of avoiding a custom header, and be completely HTTP/REST conform. There may be some performance disadvantage, but it could be mitigated with some targeted caching.
Of course you can go with custom header if you want to, but normally REST would imply that the client goes in with no prior knowledge other than mime-types and the HTTP protocol. A custom header implies out-of-band prior knowledge.

Why Having a CSRF protection in a REST context doesn't make sense?

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).

How do CSRF tokens protect from malicious GET followed by POST in another tab

I know I am missing something, but please help me understand. Consider this situation:
I have a website called goodbank.com. URL http://goodbank.com/transfer/ serves a HTML page on GET with a form to transfer money to another account. The form has a random token to prevent CSRF attack. On the server, token validity is checked on POST and the corresponding controller allows only authenticated sessions.
Let's say that in my browser, I login to goodbank.com/. In another tab, I go to robgoodbank.com. As part of the served page, it has javascript to do AJAX request to goodbank.com/transfer/ to get a valid form. It then fills in other fields in the form and does a POST. My account is cleaned out :(
How does existing protection schemes protect against such an attack?
Thanks in advance.
Unless your server allows Cross Origin Resource Sharing, the browser will reject the XMLHttpRequest. As per the link, the XMLHttpRequest sends the Origin header containing the domain from which the request originates. If the server does not respond with Access-Control-Allow-Origin containing a wildcard of that domain, the browser will reject the request. There are actually a number of Access-Control- headers to control access including allowable methods, etc.
For extra protection, your server should check the Origin if it is present and the Referer HTTP header, which will be "http://robgoodbank.com" in your example, and you can also reject the request.
These are by no means foolproof, but do provide extra layers of protection. There are mechanisms (such as extensions) to spoof the Referer, but those would have been employed by the user unless their browser has been compromised in some way. If their browser has been compromised they are in a lot more trouble...