Is it safe to serve jsonp if I require authentication headers? - javascript

I want to serve jsonp so other sites can get json data from my site. I understand that this would be dangerous if I used cookies to authenticate users, because browsers would send the cookies with all requests to my site, so a malicious page could make authenticated requests on my users' behalves without asking them.
All requests to my service have to be authenticated with a special header set on the request, X-AG-AUTH. A secret token identifying the user must be set in that header.
Would a malicious site be able to get data from my service via jsonp without the user providing the secret token?

Well, requiring a custom header for a jsonp call would render the jsonp call useless for requests coming from other domains, because your callers wouldn't be able to set those headers.
You could use a somewhat similar approach: require a CSRF-prevention-style token passed as a parameter in a POST request. This would require you to share both the logic for generating these tokens and a secret key with each site you want to allow to call your endpoint. Of course, if any of those keys were ever compromised on the remote server's side, you probably wouldn't know about it until it was too late.
If you're willing to forgo functionality for folks with really old browsers, you could use regular JSON over CORS* with a parser-breaking prefix to prevent cross-site script inclusion.
I'm assuming your data is not something you want to be made public, in which case you're hopefully also requiring SSL.

Related

Is it safe to use php proxy to do https request in javascript?

As you know you can not make http requests to sites that do not have the http header that allows it using JavaScript in browsers because of CORS. I need to make https requests containing sensitive data. I do not want to get in touch with this sensitive data, in fact all this will be client side with javascript, only for the reason mentioned above I need to use a php proxy such as CORS Anywhere or my own, the question is: if I use these proxies to make https requests directly to the direct interested server, will the proxy have any information regarding the data sent? Sorry for my bad english, I use the translator.

CSRF and CORS with Django (REST Framework)

We're in the process of moving our frontend into a separate project (out of Django). It's a Javascript single page application.
One of the reasons is to make it easier for our frontend developers to do their work, not having to run the entire project -- including the API -- locally. Instead, we'd like them to be able to communicate with a test API we've set up.
We've managed to solve most of the CORS/CSRF issues along the way. But now we've run into something I can't find a solution for anywhere, despite reading lots of documentation and SO answers.
The frontend and the API are served from different domains (during development localhost and test-api.example.com). Until now, while served from the same domain, the frontend has been able to get the CSRF token from the csrftoken cookie set by the API (Django). But when served from different domains, the frontend (localhost) can't access the cookies of the API (api-test.example.com).
I'm trying to figure out a way to work around this, to somehow deliver the CSRF token to the frontend. The Django docs recommend to set a custom X-CSRFToken header for AJAX requests. Would we compromise the CSRF protection if we similarly served the CSRF token in every response as header and (via Access-Control-Expose-Headers) allowed this header to be read by the frontend?
Given that we've set up CORS properly for the API (i.e. only allowing certain domains to do cross origin requests to the API), JS on 3rd party sites should not be able to read this response header, thus not be able to make compromising AJAX requests behind the back of our users, right? Or did I miss something important here?
Or is there another, better way to achieve what we want?
I didn't understand your question at first, so allow me to summarize: you can't get the CSRF token from the cookie on the client because the Same Origin Policy blocks you from accessing cross-domain cookies (even with CORS). So you're suggesting that the server transmit the cookie to the client in a custom header instead, and are wondering if that's secure.
Now, the documentation does make a suggestion for how to transmit the token if you're not using the cookie: put it in the response body. For example, you could use a custom meta tag. When it comes to security I lean towards using recommended solutions rather than trusting my own analysis of something new.
That caveat aside, I don't see any security problem with what you're suggesting. The Same Origin Policy will prevent a third-party site from reading the headers just as it will the body, and you can opt in to reading them from your client domain with the CORS Access-Control-Expose-Headers header.
You might find this answer interesting, as it lays out the advantages and disadvantages of various CSRF token schemes. It includes the use of a custom response header, and—to the point of your question—confirms: "If a malicious user tries to read the user's CSRF token in any of the above methods then this will be prevented by the Same Origin Policy".
(You might want to look into whether you need Django's CSRF protection at all with your SPA. See this analysis, for example. That's outside the scope of this question, though.)
Assume you already have corsheaders installed. Write a Django middleware and include it in your MIDDLEWARE settings:
from django.utils.deprecation import MiddlewareMixin
class CsrfHeaderMiddleware(MiddlewareMixin):
def process_response(self, request, response):
if "CSRF_COOKIE" in request.META:
# csrfviewmiddleware sets response cookie as request.META['CSRF_COOKIE']
response["X-CSRFTOKEN"] = request.META['CSRF_COOKIE']
return response
expose the header in your settings:
CORS_EXPOSE_HEADERS = ["X-CSRFTOKEN"]
When you make a GET API call from you JS, you should get X-CSRFTOKEN from response header, go ahead and include it in the request header when you make POST PUT PATCH DELETE requests.

Is a SSL'ed JSON API that uses cookies for authentication and nonces generally secure?

If I build an SSL'ed API that authenticates with a session ID held within a cookie, adds a nonce as a query parameter, and always responds with a JSON 'Object' response (as opposed to a JSONP-style response with a callback), is it secure in general, and in particular against XSRF?
The intent with such an API to only have it available to pages on my own domain, and to be free to expose private data (such as username and emails) through this API (but not be consumable by other domains)--and retain a reasonable amount of simplicity for developers on the team.
Let me at least share what I understand about this approach, and why I think it's secure. Please enlight me if wrong!:
A <script> tag dropped on a 3rd-party domain to our site would send my cookies, but would not be able to parse the JSON object response (and the response would always deliberately be a JSON object at the top level). Also, I need to make sure that API calls that affect state on the server are all protected by non-GET method access, because <script> tags must use GET and so can not cause havok by attempt to call state-changing calls (in other words, the API would be adherent to REST in so far as HTTP methods go). Also, I deliberately do not support JSONP because it would be a security hole.
Man-in-the-middle used to hijack cookies (the session) is not a concern because I'm using SSL with valid certificates.
Replay attacks are a temporally limited concern because of the use of a nonce will limit how long one could send in a replay of an HTTPS request, because the server will make sure that the API call is only valid for a small amount of time in a typical nonce-validating way.
XMLHttpRequest can not make cross-domain calls, so it can't request anything from my site.
CORS (Cross ORigin Resource Sharing) is not of concern because I don't have a crossdomain.xml file or any other advertisement of cross-domain support associated with HTML 5.
An iframe in a 3rd-party site doesn't matter because even though it can load my page graphically, the host site can't access any data within that iframe, and because I've made no attempt to support cross-domain iframe communication (so they can attempt to set # on the iframe URL like folks do to enable communication between cross-domain iframes, but my page won't be responsive to it).
EDIT:
A nonce would also protect against even cross-domain GET requests (i.e., <script> tags) as russau says. In thinking on that specifically, I like the idea of asking for a nonce in a 'POST' API call that is not itself nonce protected; it should be the case that only XmlHTTPRequest's on the same domain can then generate a nonce to begin with. This seems to be a simple way of making the generation of nonce's developer-friendly. (i.e., nothing server-side for the website/javascript developers--just ask for your nonce from the same API you are using to develop against, and make requests with that nonce until you get a 'bad nonce' response--then ask for a new one, and repeat.
The only attack I can imagine is DNS rebinding. If your webserver is configured properly (a name-based vhost should be sufficient) you should be pretty safe though.

Retrieving cookies with javascript XMLHTTPReq

Just wondering if it's possible to use an XMLHTTPReq to login to a website, and store the cookie. Specifically I'm after the PHPSessionID from the website I am logging into.
I then want to pass this cookie into another request to submit a form.
Any ideas of how to do this?
Cheers,
Nick
You will be able to get your own site's cookies from document.cookie. In the AJAX callback, use a library to parse the value and read the cookie you're looking for.
Of course, if the server sets the cookie HttpOnly (which it should be doing), it won't be available in document.cookie.
At this pont, you need to reevaluate what you're doing:
If the form points to your website, your server script would have access to the cookie anyway.
If you're sending the user's session ID to another domain, why? This is a huge red flag that screams security problem.
If you're logging in to another site, then no – the same-origin policy prevents you from accessing another site's cookies.
Edit: Since this is for your own use, you can do this in a way you're not limited by the browser's origin restrictions. Some thoughts:
You could make a Chrome extension. Extensions aren't subject to origin restrictions, and the development model and API is pretty much the same as what you'd do on a regular web page.
You could use Node, which has no restrictions. You'd be able to invoke your script from the command line, but the API is going to be slightly different that what you'd use in a web page.
Use your language and framework of choice to POST to the login page, get the Set-Cookie header in the response, and use it to send a Cookie header in another POST to the form target.
You can only send cross-origin requests using XHR if both the browser and server support CORS. Additionally, the third party site needs to allow your site to send such requests and to receive its responses. If it doesn’t, you aren’t allowed to send the request or receive its response respectively.

Calling HTTPS from HTTP through AJAX for login

I know its violates the Same origin policy, and that is why it is not possible through simple ajax request. I could use JSONP. But using JSONP for login doesn't sound secure ( no post only get ).
So is there a more secure way of implementing login into https through ajax ?
Not only does it violate the same origin policy, but since the page you are calling from is insecure it has the potential to be interfered with and leak all the data you are trying to keep secure.
Use HTTPS for the entire process.
Better yet, keep using HTTPS while people are logged in, otherwise you will have the Firesheep problem.
As we've discussed in the comments below, this is what Facebook does for their registration page, although there are some vulnerabilities to this method. While it won't appear secure to the user (no lock icon), the actual request is done over HTTPS. If you controlled the entirety of the receiving page, there would be nothing less secure about doing a JSONP request over GET. However, a man-in-the-middle attack could modify the receiving page on load, and cause the returned credentials to be sent to an attacker.
On the plus side though, no one that's just sniffing packets is going to be able to get the credentials: an attack would have to be fairly targeted.
Regarding cookies, technically, JSONP could "return" cookies; you'd just return name-value pairs of the cookies you wanted to set, and have a function on the receiving page set them.
But unless the browser treats <script>s differently, and it might, you should be able to set a cookie in the normal way using the Response Headers of your JSONP response.

Categories