views:

216

answers:

4

I want to make an XMLHttpRequest to a secure uri (https://site.com/ajaxservice/) from javascript running inside a nonsecure page (http://site.com/page.htm). I've tried all kinds of nutty stuff like iframes and dynamic script elements, so far no go. I know I am violating 'same origin policy' but there must be some way to make this work.

I will take any kind of wacky solution short of having the SSL protocol written in javascript.

+1  A: 

I don't think this is possible. Previously asked: http://stackoverflow.com/questions/1105934/ajax-http-https-problem

dkamins
it's probably sort of possible using iframes and bookmark hashes but that is ugly ugly ugly and only secure if the part after the hash is not sent to server.
amwinter
+1  A: 

You can't circumvent cross-domain origin with XHR (well, only in Firefox 3.5 with user's permission, not a good solution). Technically, moving from port 80 (http) to 443 (https) is breaking that policy (must be same domain and port). This is the example the specification itself sites here - http://www.w3.org/Security/wiki/Same_Origin_Policy#General_Principles.

Have you looked into JSONP (http://en.wikipedia.org/wiki/JSON#JSONP) or CSSHttpRequests (http://nb.io/hacks/csshttprequest)?

JSONP is a way to add a <script> tag to a page with a pre-defined global callback across domains (as you can put the <script>s src to anywhere on the web). Example:

<script>

    function globalCallback (a) { /* do stuff with a */ }

And then you insert a <script> tag to your other domain, like so:

    var jsonp = document.createElement('script');
    json.setAttribute('src','http://path.to/my/script');
    document.body.appendChild(jsonp);

</script>

And in the source of the external script, you must call the globalCallback function with the data you want to pass to it, like this:

 globalCallback({"big":{"phat":"object"}});

And you'll get the data you want after that script executes!

CSSHttpRequests is a bit more of a hack, so I've never had the need to use it, though feel free to give it a try if you don't like JSONP, :).

Dan Beam
ok, but {big {phat object}} is defined in the external script. no way to pass in data, is there?
amwinter
when you call the `globalCallback` it's passing it to the originating page's function ... "pass[ing] in data"
Dan Beam
returning it to the originating page. I want to pass data to the remote script without putting it in the url.
amwinter
you're not putting it in the URL...you're just calling a global function. ignore the `src` of the tag in this instance. it's just like you declared a `function` in a `<script>`, and then called it later in another `<script>` on the same page (because you really are).
Dan Beam
oh, I see what you're saying - you want to send data to your remote script (not get it from it). you could store it in a secure cookie or in the GET/POST of an SSL page (the GET/POST is encrypted, like I've said) if you want it to be functionally hidden.
Dan Beam
+1  A: 

That won't work by default due to the same origin policy, as you mentioned. Modern browsers are implementing CORS (Cross-Origin Resource Sharing) which you could use to get around this problem. However this will only work in Internet Explorer 8+, Firefox 3.5+, Safari 4+, and Chrome, and requires some server-side work. You may want to check out the following article for further reading on this topic:

You can also use JSONP as Dan Beam suggested in another answer. It requires some extra JavaScript work, and you may need to "pad" your web service response, but it's another option which works in all current browsers.

Daniel Vassallo
solid. would love to see a solution for older browsers but this is clean and works today.
amwinter
JSONP or a proxy page (i.e. http://path.to/me?get=https://path.to/get)
Dan Beam
There are solutions for older browsers, using a reverse proxy, but you will lose the benefit of SSL... I guess you aren't willing to sacrifice that, because in that case you could just have served your `/ajaxservice/` from http (or both).
Daniel Vassallo
You won't lose the benefits if you use https:// in the `src` of the `<script>`...
Dan Beam
@Dan Beam: That would pop up some browser warning I guess, won't it? Saying that you have mixed secure and non-secure content?
Daniel Vassallo
sending data in https url is not ok for this specific app -- not fair to my users to have passwords in server logs
amwinter
@amwinter - the `GET` and `POST` data of `https://` calls is encrypted as well (just learned that recently). @Daniel No, the warning only shows up when the source page is `https://` and you try to access non SSL assets (https://mypage.com/ tries to get http://mypage.com/something.js).
Dan Beam
trust me on the ( http + https script != warning ) thing, I just tried it from this page to a secure script, :)
Dan Beam
@Dan Beam: True, it's past my bed time :) Let me update my answer with reference to yours.
Daniel Vassallo
@Dan Beam. yes, the transmission is encrypted, but my server logs will still have the URI in plaintext.
amwinter
You're right about not wanting to pass sensitive parameters through the query string. With JSONP you cannot issue a POST request.
Daniel Vassallo
@amwinter: Use easyXDM (http://easyxdm.net/wp/) it will enable you to do this easily even in older browsers - and its much easier to set up than CORS as it has no server side requirements! Check out the ajax example here http://consumer.easyxdm.net/current/example/xhr.html and read more about it here http://easyxdm.net/wp/2010/03/17/cross-domain-ajax/
Sean Kinsey
@seankinsey am I wrong or is easyxdm a cool wrapper around window.opener and iframe hash methods? not that there's anything wrong with that.
amwinter
postMessage, window.opener (nix), window.name, FIM (hash fragment) and friends :) This solves the cross domain issue (http vs https) meaning that you can run the XHR in the domain that it is requesting from, and pass data across the boundry using easyXDM. Thats what that last sample shows.
Sean Kinsey
@seankinsey your live example is hard to follow. the two helper pages are confusing. is there a self-contained example?
amwinter
What do you mean by 'helper pages' ? There is the '/current/xhr.html', which exposes the easyXDM RPC interface, and then there is the '/current/example/xhr.html' that consumes the interface. If you are referring to 'local' and 'remoteHelper' then you can disregard these now. I just forgot to update the examples :)
Sean Kinsey
+1  A: 

You said you would take anything short of having the SSL protocol written in JavaScript... but I assume you meant if you had to write it yourself.

The opensource Forge project provides a JavaScript TLS implementation, along with some Flash to handle cross-domain requests:

http://github.com/digitalbazaar/forge/blob/master/README

Check out the blog posts at the end of the README to get a more in-depth explanation of how it works.

dlongley
cool man! this is useful
amwinter