5

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.

amwinter
  • 3,121
  • 2
  • 27
  • 25

3 Answers3

5

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.

Community
  • 1
  • 1
Daniel Vassallo
  • 337,827
  • 72
  • 505
  • 443
  • solid. would love to see a solution for older browsers but this is clean and works today. – amwinter May 28 '10 at 02:27
  • 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 May 28 '10 at 02:29
  • You won't lose the benefits if you use https:// in the `src` of the ` – Dan Beam May 28 '10 at 02:31
  • @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 May 28 '10 at 02:33
  • sending data in https url is not ok for this specific app -- not fair to my users to have passwords in server logs – amwinter May 28 '10 at 02:37
  • @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 May 28 '10 at 02:45
  • trust me on the ( http + https script != warning ) thing, I just tried it from this page to a secure script, :) – Dan Beam May 28 '10 at 02:47
  • @Dan Beam: True, it's past my bed time :) Let me update my answer with reference to yours. – Daniel Vassallo May 28 '10 at 02:47
  • @Dan Beam. yes, the transmission is encrypted, but my server logs will still have the URI in plaintext. – amwinter May 28 '10 at 02:50
  • You're right about not wanting to pass sensitive parameters through the query string. With JSONP you cannot issue a POST request. – Daniel Vassallo May 28 '10 at 03:01
  • 1
    @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 May 28 '10 at 09:32
  • @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 May 28 '10 at 10:50
  • 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 May 28 '10 at 11:06
  • @seankinsey your live example is hard to follow. the two helper pages are confusing. is there a self-contained example? – amwinter May 28 '10 at 11:18
  • 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 May 28 '10 at 13:27
  • Hello @amwinter: Can you please provide the code ( by git ) /snippet in making the secured call from nonsecured page please. – Pradeep kumar Jan 16 '20 at 17:03
4

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
  • 3,632
  • 2
  • 23
  • 27
  • ok, but {big {phat object}} is defined in the external script. no way to pass in data, is there? – amwinter May 28 '10 at 02:23
  • when you call the `globalCallback` it's passing it to the originating page's function ... "pass[ing] in data" – Dan Beam May 28 '10 at 02:30
  • returning it to the originating page. I want to pass data to the remote script without putting it in the url. – amwinter May 29 '10 at 12:15
  • 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 ` – Dan Beam Jun 02 '10 at 03:27
  • 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 Jun 02 '10 at 03:30
2

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
  • 2,078
  • 14
  • 17