Can CSRF Be Circumvented By JSONP - jsonp

I'm very new to CSRF protection so please excuse if I make poor assumptions or if I'm missing something, but I'd like to make sure I'm doing all I can to prevent CSRF. From my research so far, I've found the following:
CSRF can be thwarted (and is probably best thwarted) by placing a nonce parameter within the request body of all HTML POSTs, only using POSTs to modify data, and on the server side verify the token is valid before processing the request.
A malicious website can send requests to my site (thwarted by the nonce), but they can't read responses because of same-origin policies in place on browsers. Assuming that someone is using a secure browser, a malicious site cannot GET a page from my site using AJAX, read the nonce, and use it for themselves.
Script tags are not bound by same-origin policies in most (possibly any) browsers and can therefore allow for content to be read from other sites.
When I got to point 3 I decided to try to get at HTML content in Chrome using JSONP; I opened up my console (with a page not from localhost) and ran the following code:
$.ajax({
url: "http://localhost:8080/my-app/",
dataType: "jsonp",
jsonp: "alert"
}).done(function(data) {
alert(data);
});
What I received in the console window was the this:
Resource interpreted as Script but transferred with MIME type
text/html
As far as I can tell the browser is essentially telling me that it received the content, proceeded to parse the response, but stopped because the type was not application/json. So finally, my question is, can this be compromised? Even though the browser failed to parse the response as JSON, it does have the response. Is there a way that this response could be parsed as HTML, grab my CSRF nonce, and compromise the protections I'm trying to enforce? It would seem to me (and I hope this to be true) that browsers will not allow this, just like they don't allow cross domain requests in the first place for basically all other communication, and that's what we as developers are relying upon (in addition to same-origin policies) to protect our sites. Is my thinking correct?

Related

Vue--How do I make the <a> tag carry the request header?

How do I make the tag carry the request header? I use the <a> tag to download. And I need to carry a token in the request header.
When you use a tag to download files or link to any document, in general, it is not possible to manipulate extra headers! Browsers will send the typical headers. To solve this problem, following are the alternative solutions.
Your token must be query parameter in the URL so that back-end server can read it.
Or you can use cookies to save the token and browser will ensure that cookies are sent for your request automatically. (For security, ensure that you cookie is HTTP only and rejects CORS requests)
Alternately, if you are not really after downloading the file or simply trying to show on browser, then you can use XHR or fetch where you are free to manipulate headers.

CSRF tokens - Do we need to use them in most cases?

So I essentially went on an epic voyage to figure out how to implement CSRF tokens. 20 years later - and now I feel like I just wasted my life. haha
So basically after making malicious test-clients and doing some re-reading it looks like it's virtually not a problem if:
1) You don't allow outdated browsers(they don't enforce CORS)
2) You don't allow CORS by setting the "Access-Control-Allow-Origin" on the resources.
3) You use a JSON API(all requests-responses is sending JSON).
4) You take care of XSS(they can inject code that will run from same origin ).
So as long as you take care of XSS(Reactjs! Holla) - all of the above(minus the old browser part I guess) is basically common practice and an out-of-the-box setup - so it seems like a waste of time to worry about csrf tokens.
Question:
So in order to avoid throwing my laptop under a moving car - is there any reason that I did all that work adding CSRF tokens if I am already adhering to the 4 prevention strategies mentioned above?
Just Fun Info - wanted to share one juicy find my tests came across:
The only ify thing I found with my tests is "GET" requests and an image tag
e.g.
<img src="http://localhost:8080/posts" onload={this.doTheHackerDance} />
The above will pass your cookie, and therefore access the endpoint successfully, but apparently since it is expecting an image - it returns nothing - so you don't get to do the hacker dance. :)
BUUUUT if that endpoint does other things besides return data like a good little "GET" request(like update data) - a hacker can still hit a "dab!" on ya (sorry for viral dance move reference).
tl;dr - Requiring JSON requests mitigates CSRF, as long as this is checked server-side using the content-type header.
Do we need to use them in most cases?
In most other cases, yes, although there are workarounds for AJAX requests.
You don't allow outdated browsers(they don't enforce CORS)
You don't allow CORS by setting the "Access-Control-Allow-Origin" on the resources.
CORS is not required to exploit a CSRF vulnerability.
If Bob has cookies stored for your site, CORS allows your site to allow other sites to read from it, using Bob's browser and cookies.
CORS weakens the Same Origin Policy - it does not add additional security.
The Same Origin Policy (generally - see below for caveat) does not prevent the request from being made to the server, it just stops the response being read.
The Same Origin Policy does not restrict non-Javascript requests in any way (e.g. POSTs made by <form> or <img> HTML directives).
Browsers that do not support CORS, also do not support AJAX cross-origin requests at all.
Therefore while not outputting CORS headers from your site is good for other reasons (other sites cannot access Bob's session), it is not enough to prevent CSRF.
You use a JSON API(all requests-responses is sending JSON).
Actually, if you are setting the content-type to application/json and verifying this server-side, you are mitigating CSRF (this is the caveat mentioned above).
Cross-origin AJAX requests can only use the following content-types:
application/x-www-form-urlencoded
multipart/form-data
text/plain
and these requests are the only ones that can be made using HTML (form tags or otherwise).
You take care of XSS(they can inject code that will run from same
origin ).
Definitely. XSS is almost always a worse vulnerability than CSRF. So if you're vulnerable to XSS you have other problems.
BUUUUT if that endpoint does other things besides return data like a
good little "GET" request(like update data) - a hacker can still hit a
"dab!" on ya (sorry for viral dance move reference).
This is why GET is designated as a safe method. It should not make changes to your application state. Either use POST as per the standard (recommended), or protect these GETs with CSRF tokens.
Please just follow OWASP's guidelines: "General Recommendation: Synchronizer Token Pattern". They know what they're doing.
CSRF counter-measures are not hard if you're using a framework. It's dead simple with Spring Security for example. If you're not using a security framework, you're screwing up big time. Keep it simple. Use one general method to protect against CSRF which you can use on many types of projects
CSRF is orthogonal to CORS . You are vulnerable even if you disallow CORS on your server and your users use the latest Chrome. You can CSRF with HTML forms and some JavaScript.
CSRF is orthogonal to XSS . You are vulnerable even if you have no XSS holes on your server and your users use the latest Chrome
CSRF can happen against JSON APIs. Rely on Adobe keeping Flash secure at your own peril
The new SAMESITE cookie attribute will help, but you need anti-CSRF tokens until then.
Keep reading

Why token-based authentication is better than cookie-based authentication in CORS/Cross-domain scenario?

I have seen in many places that one of the benefits of token-based authentication over cookie-based authentication is it is better suite for CORS/cross-domain scenario.
But why?
Here is a CORS scenario:
An HTML page served from http://domain-a.com makes an <img> src
request for http://domain-b.com/image.jpg.
Even if there's a token on my machine, how could the mere <img> tag know where to find and send it?
And according to here, it is suggested to store JWT as cookie, so how could that survive the CORS/cross-domain scenario?
ADD 1
Token-based authentication is easier to scale out than session-cookie one. See a related thread here: Stateless web application, an urban legend?
Just for clarification: Requests to any subdomain that you have are also considered as cross origin request (ex. you make request from www.example.com to api.example.com).
A simple <img> GET request to another origin is, indeed, cross origin request as well, but browsers are not using preflighted (OPTION) requests if you use GET, HEAD, POST requests only, and your Content-Type header is one of the followings:
application/x-www-form-urlencoded
multipart/form-data
text/plain
Therefore simple <img> request to another origin won't have problem (regardless if subdomain or totally another domain), as it won't go through preflight, unless it requires credentials, because when you add Authorization header, the request needs to go through preflight.
About storing in localstorage vs in cookie: Localstorage has single origin policy, meaning you cannot access the data you have stored from the subdomain, ie, example.com cannot access data in localstorage of api.example.com. On the other hand, using cookies, you can define which subdomains can access to the cookie. So you can access your token in stored in cookie and send it to server with your requests. Cookies also doesn't allow to access data across different domains.
Hope this helps.

JSONP check header response

if I get data from an external website in JSONP form, how do I access the http header response? I have heard this may be difficult but my experience is that everything is possible.
Nope.
This is completely impossible.
The whole point of JSONP is to bypass the same-origin policy by passing a result through executable Javascript code.
Other than JS code generated by the remote server, you cannot get any information.

How do REST APIs work with JavaScript when the same-origin policy exists for browsers?

I am working with Flickr's REST API and it's working fine. By that, I mean I'm making an AJAX call to the Flickr API and getting a JSON object back, parsing the object, etc. etc.
But this raises a question in my mind. If browsers follow the same-origin policy, then how can they make these types of API requests?
This DEMO fiddle is working, but it sends a cross-domain request to the Flickr domain.
How does this cross-domain request work?
The cross-domain request:
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?id=" +
id + "&lang=en-us&format=json&jsoncallback=1");
What you need to understand is that, while browsers do enforce the same origin policy (SOP), there are exceptions when SOP is not enforced. For example, if you have an HTML page - you can insert <img> tags that point to images on any domain. Therefore, the SOP doesn't apply here and you are making a cross-origin HTTP GET request for an image.
The demo you linked to works since it uses a mechanism that works in a similar way. The mechanism is called JSONP - http://en.wikipedia.org/wiki/JSONP and I suggest you read the wiki entry and some other blog posts. In essence, JSONP dynamically injects <script> tags to send a request to any domain (the parameters of the request are added as URL query params), since the same origin policy does not apply to <script> tags (as it doesn't apply to <img> tags).
Another way to invoke REST APIs on other domains is to use the cross-origin resource sharing mechanism (CORS) - http://en.wikipedia.org/wiki/Cross-origin_resource_sharing. In essence, this mechanism enables that browsers don't deny cross-origin request, but rather ask the target service if it wants to allow a specific cross-origin request. The target service tells the browser that it wants to allow cross-origin requests by inserting special HTTP headers in responses:
Access-Control-Allow-Origin: http://www.example.com