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.
Related
From what I've read, CSRF prevention seems to focus on (1) making GET requests side-effect-free and (2) using only POST requests with CSRF tokens to alter state. It seems to me, though, that this assumes that the only objective an attacker might have would be to maliciously update the victim website. What if the attacker just wants information which can be retrieved via a GET request? Couldn't someone embed a sensitive resource from the victim site into the attacking site and interact with it via Javascript?
So my questions are (1) is that possible, and (2) how do you prevent it?
An attacker could include the following script on their page:
$.get('http://vulnerable.example.com/json')
However, due to the Same Origin Policy, the JavaScript on the attacker's domain couldn't read the response. The same origin policy checks whether the domain, protocol and port match - if they don't the JavaScript will encounter a security error when trying to read the response. For example, this is the warning Chrome gives when trying to access an IFrame from another domain - this is exactly the same mechanism that will protect the JavaScript response.
Uncaught SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': blocked a frame with origin "http://evil.com" from accessing a frame with origin "http://vulnerable.example.com". Protocols, domains, and ports must match.
So in summary, POST requests must use a CSRF token as the POST request will still be made even though the response cannot be read and GET requests are not normally a cause for concern as the response cannot be read and they are non destructive. There was the issue with JSON Hijacking, but you have to go back as far as Firefox 3 to find a browser vulnerable to this. See Is JSON Hijacking still an issue in modern browsers?
If an attacker had a way to receive the server's response to the victim's request (the response would be transmitted to the victim's browser, but not transmitted to the attacker), then the attacker could potentially benefit from a CSRF GET request.
However, in a typical CSRF scenario, the attacker does not have access to the response, because it is transmitted from the server to the victim's web browser (and not transmitted to the attacker). Usually the intent is to cause some state change, such as initiating a payment, sending an email, etc, which is usually initiated by a client making an HTTP request with a method like PUT, POST, PATCH or DELETE.
This is a concept that I thought I understood, but recently found out I had all wrong. I've looked all around the internet and find plenty of examples of small details and code snippets, but I still lack an understanding of what it prevents and why it prevents it and for whose sake. So this is more of a request for a high-level explanation than a question.
Anyways, here's what I THINK I understand about it:
Let's say I have domain A.com and domain B.com. Each on their own apache servers with their own IP addresses.
I load an html file from domain A.com into a browser. The browser executes a POST XMLHttpRequest to B.com/doStuff.php, which fails because the same-domain-policy was set.
So:
Who's same-domain-policy is relevant? I think the answer is B.com/doStuff.php's... right? So when A sends the request, B checks the request headers for an origin and says "whoops, different domain, won't listen to you". Or does A send the request, B responds with headers that specify "same-domain-policy", and then the browser checks that because same-domain-policy was specified, and the domain from the headers of the A request don't match the one from the B request the BROWSER refuses to send out the xhr?
If that's the case, it seems that the point of not allowing cross-origin-requests is because "I don't want anyone other than me accessing my API". Is that all? Because wouldn't you want to solve that with some kind of authentication instead? Couldn't someone just construct an HTTP request with a fake origin header (simply lie)?
Or is this somehow supposed to protect the user? If that's the case, how is preventing them from calling your API ever going to protect anyone?
I'm so confused...
Who's same-domain-policy is relevant?
The server receiving the request decides.
... the BROWSER refuses to send out the xhr?
No, the server refuses to respond. To be more exact, in modern browsers it is done by preflighted requests. It means that for each cross-origin request, first an OPTIONS request is sent automatically by the browser whose headers are the exact same as the intended request will have but with no request body. The server responds also with headers only. Access-Control headers in the response will let the client browser know whether the request would be fulfilled according to the server's policies. In a sense the browser is preventing the request, but only because it already exchanged a request/response pair with the server and knows that there would be no point to attempt the request. If you forge a request in such a case, the server will still deny serving it.
The idea is that you don't want to access server b from server A via Javascript. If you're interacting with an API, you would use javascript to make a call to your own server's backend code, which would then make a call to the other server.
I know there is an almost duplicate question, but the answer is not satisfactory at all.
I need to do geocoding using the Openstreetmap service which runs over HTTP.
My site runs over HTTPS.
It seems impossible to do JSONP request from https to http, browser (Chrome) complains about insecure content.
Any solutions?
The reason that the browser complains about insecure content is that the content is insecure. The entire purpose with a secure page is that all of it is secure, and can be trusted.
You can set up a proxy page in your secure site that requests the insecure content. There you should verify the content before it's sent to the browser, so that it is actually secure, not just pretending to be secure.
If you want to make a POST request to an external service that runs under HTTP while the initial request is coming from HTTPS it will always be considered as insecure.
There's, as far as I know, no way around it.
What you can do, is POST to your backend which send another POST request to the service that is running under HTTP. From there just return the value returned by the HTTP service.
For whom it may concern, this is how I sorted it out myself.
1) my Javascript code calls an AJAX page on my server with the parameter I need to forward to the service
2) the AJAX page makes a request via CURL using the address
3) I sanitize the response and turn it into JSON
4) with Javascript's callback-on-success I use the data
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.
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.