Look Ma, Cross-Domain Scripting!

Ajax, as I've stated time and time again, is sweet. So what is problem? XMLHTTPRequest requires that the called scripts that execute server side and return information to the client must reside on the same domain. This has irked me time and time again during my exploration and experimentation of the Web 2.0 world.

Enter JSON Web Services and dynamic script tags. This beauty allows for Ajax-like communication across domains without requiring page loads. Right right right...so how do you use it? Read on...

First, lets clarify what JSON (JavaScript Object Notation) is. Wikipedia explains that JSON is just a way to structure object data in a way that is easily interpreted...primarily with JavaScript. Here's some examples from Wikipedia:

JSON Example:

JavaScript:
  1. bork({"menu": {
  2.   "id": "file",
  3.   "value": "File",
  4.   "popup": {
  5.     "menuitem": [
  6.       {"value": "New", "onclick": "CreateNewDoc()"},
  7.       {"value": "Open", "onclick": "OpenDoc()"},
  8.       {"value": "Close", "onclick": "CloseDoc()"}
  9.     ]
  10.   }
  11. }});

Which is the same as this XML Example:

XML:
  1. <menu id="file" value="File">
  2.   <popup>
  3.     <menuitem value="New" onclick="CreateNewDoc()" />
  4.     <menuitem value="Open" onclick="OpenDoc()" />
  5.     <menuitem value="Close" onclick="CloseDoc()" />
  6.   </popup>
  7. </menu>

So...if JSON just the data representation part of things, how does it work similarly to Ajax?

Now we're getting into the Web Services side of things. The quick answer: When you dynamically create <script> tags on a page, the JavaScript source is executed immediately. Now, as most experimental web developers may well know, you can reference remote JavaScript source in a <script> tag. Which means....if you dynamically create a script tag that references a source on another domain, and that source outputs JSON, you are as good as gold!

Here's the step by step: (I use a JavaScript Object I found over at Dan Theurer's Blog for the dynamic adding of script elements...it helps avoid duplicate script tags).

First, lets make the remote file that outputs JSON. (obviously, most cases will have the data dynamically generated...but I'll use a static example as the generation of this data is trivial)

file: remote_file.php

PHP:
  1. <?php
  2. echo 'bork({"Image": { "Width":500, "Height":250, "Title":"Giant Cow", "Thumbnail":{"Url":"http://someurl.com/image/1234", "Height": 75, "Width": 150}}});';
  3. ?>

Here's the html file we want the user to see/interact with:

file: client.html

HTML:
  1. <head><title>Test</title></head>
  2. <script src="js/jsr_class.js" type="text/javascript"></script>
  3. <script type="text/javascript">
  4. function addScript()
  5. {
  6.   var obj=new JSONscriptRequest('http://someurl.com/remote_file.php');     
  7.   obj.buildScriptTag(); // Build the script tag     
  8.   obj.addScriptTag(); // Execute (add) the script tag
  9. }//end addScript
  10.  
  11. function bork(data)
  12. {
  13.   var text='';
  14.  
  15.   if(data==null)
  16.     alert('error');
  17.   else
  18.   {
  19.     text='Image Title: ' + data.Image.Title + '<br />';
  20.     text+='Width: ' + data.Image.Width + '<br />';
  21.     text+='Height: ' + data.Image.Height + '<br />';
  22.     text+='Thumbnail Data: ' + data.Image.Thumbnail.Url;
  23.     text+=' (' + data.Image.Thumbnail.Width + 'x' + data.Image.Thumbnail.Height + ')<br />';
  24.   }
  25.   document.getElementById('output').innerHTML=text;
  26. }//end bork
  27. </script>
  28. <a href="#" onClick="addScript(); return false;">Click to Get Stuff</a>
  29. <div id="output"></div>
  30. </body>
  31. </html>

Thats all there is to it! Simple and slick.

Discuss This Article


21 Responses to “Look Ma, Cross-Domain Scripting!”

  1. AvatarEdward Clarke

    Good example of scripting around browser securities. Should see greater use of this in the future. It still limited by browser support though.

    Reply to this comment.
    1
  2. AvatarBill Wilson

    I’m looking at your code and it doesn’t explain exactly how this works, it just provides us with code to use. I’m curious as to what makes JSON work and what differences JSON has from XML. Is there any draw-backs or negative effects of using your solution? Is it a hack that will be fixed in the future?

    Reply to this comment.
    2
  3. pingback pingback:
    BorkWeb » Blog Archive » Ajax; Templating; and the Separation of Layout and Logic

    [...] I have often mentioned my process of expanding my proficiency of Ajax. Through my journey I have made a number of wrong turns and hit my share of stumbling blocks. All of that has been a learning experience and I’m learning still. I began fiddling with XMLHttpRequest as many do - blissfully ignorant of the many frameworks that exist to make Ajax super easy. My code was bloated with some neat…’features’ (pronounced: bugs). [...]

    Reply to this comment.
    3
  4. pingback pingback:
    No Sheep » Behaviour, Return of Clean HTML

    [...] As we’ve begun adopting Ajax, JSON, and similar JavaScript heavy technologies a problem quickly arose. Suddenly our clean HTML was being cluttered with tons of script tags, onclicks, and other various event handling functions. Trying to extract this logic back out of the HTML was a definite desire for us. [...]

    Reply to this comment.
    4
  5. pingback pingback:
    BorkWeb » Practicing What I Preach

    [...] MasterWish was built using SAJAX as the tool of choice for Ajax communication but as I’ve mentioned in the past, I am a Prototype convert. My knowledge of Ajax, JSON, and general application structure has been morphing so much in recent weeks that I have held off in completely revamping the wish list site. [...]

    Reply to this comment.
    5
  6. pingback pingback:
    BorkWeb » The Case For JSON: What Is It and Why Use It?

    [...] After my post titled Look Ma, Cross Domain Scripting! a while back, I received a comment that was seeking more information. The commenter posts: I’m looking at your code and it doesn’t explain exactly how this works, it just provides us with code to use. I’m curious as to what makes JSON work and what differences JSON has from XML. Is there any draw-backs or negative effects of using your solution? Is it a hack that will be fixed in the future? [...]

    Reply to this comment.
    6
  7. Avatarbob

    crap man….at least put up a working sample so we can view. I have no idea how this really works.

    Reply to this comment.
    7
  8. AvatarMatt
    Author Comment

    I’ve updated it and it seems to work for me. Here is another example that I lifted from Yahoo.

    Reply to this comment.
    8
  9. AvatarskUte

    Your example did not work for me. The other example from yahoo only works for me in firefox, IE returns nothing. Is JSON not cross browser ?

    Reply to this comment.
    9
  10. Avatarcornwell

    wow - works great although i did have to change the sample page to get it to work

    note you must have a parameter os some type like ?a=b because the JSON script adds a timestamp to the end to prevent caching ….. “‘&noCacheIE=’ + (new Date()).getTime();”

    var obj=new JSONscriptRequest(’http://www.netlert.com/includes/crossdomaintest2.php?a=b’);

    however don’t understand this part
    “….if you dynamically create a script tag that references a source on another domain, and that source outputs JSON, you are as good as gold!”

    i just created a simple php page like so
    bbbbb”);’;
    ?>

    and added a function to my page

    function test(a, b){
    var e = document.getElementById(’output’);
    e.innerHTML = a + ” ” + (new Date()).getTime();
    e.innerHTML += b;
    }

    so I don’t see why you have to use JSON notation - anyway, i tested this on the major browsers - netscape 6.2 and up - firefox - opera, ect and it worked fine.

    However I created a loop at the bottom and there is a slow memory leak :(

    function loop(){
    addScript();
    setTimeout(”loop();”, 1000);
    }
    setTimeout(”loop();”, 1000);

    actually i take that back - I made the obj var global and in my test script I do a obj.removeScriptTag(); and it seems to fix the memory leak.

    anyway thats my input - this is awesome!!!

    Reply to this comment.
    10
  11. Avatarcornwell

    wow - this is great - you have to modify the test to get it to work

    you have to add a parameter on the end of the JSON object like so
    obj=new JSONscriptRequest(’http://www.netlert.com/includes/crossdomaintest2.php?a=b’); because the script adds a timestamp to prevent caching ‘&noCacheIE=’ + (new Date()).getTime();

    The other thing is if you are making a lot of calls over time there is a memory leak so you have to make the JSON object global so you can call obj.removeScriptTag();

    var obj;
    function addScript()
    {
    obj=new JSONscriptRequest(’http://www.netlert.com/includes/crossdomaintest2.php?a=b’);
    obj.buildScriptTag(); // Build the script tag
    obj.addScriptTag(); // Execute (add) the script tag
    }

    however i don’t understand this part “if you dynamically create a script tag that references a source on another domain, and that source outputs JSON, you are as good as gold!”

    I just created a simple php page like so
    bbbbb”);’;
    ?>

    and added my own function
    function test(a, b){
    var e = document.getElementById(’output’);
    e.innerHTML = a + ” ” + (new Date()).getTime();
    e.innerHTML += b;
    obj.removeScriptTag();
    }

    works great - this is awesome thanks!

    Reply to this comment.
    11
  12. Avatarniels marsman

    I’ve got a question about security.
    How can I, when U include a PHP page that generates JSON, restrict it to just one website?
    So no one can include the page, just by viewing the source and copy the uri.
    I tried it to check whether the HTTP_REFERER is the same as a var set in the PHP file.
    But i found that the HTTP_REFERER is not always set, you can disable it in your browser settings..

    anybody got an sollution?

    btw: nice script!

    Reply to this comment.
    12
  13. AvatarMatt
    Author Comment

    Basically what you need to do is use a ’secret key’ only known to your application (similar to what Flickr does with their API key) and output the appropriate JSON if the the key is legit. The easiest way is to first create a string you want as your key…like:

    dkdlk9090873dnv986c6980u3jf9

    Then when you are do your actual inclusion of the script, pass along a timestamp and an md5 hash of the ‘timestamp concatenated with your key’. On the PHP side of things, your script already knows the key and the passed timestamp can be concatenated with the key and md5′d then checked against the passed in md5 hash. So basically, you’ll have something like this:

    <script type=”text/javascript” src=”http://something.com/some/script.php?timestamp=123456789&hash=bf8db5cb4ec88ee6f0d537a6594fe9cc”></script>

    (the hash is an md5 of “123456789dkdlk9090873dnv986c6980u3jf9″, timestamp and key)

    On the PHP side of the world, you have the following:


    <?php
    $key='dkdlk9090873dnv986c6980u3jf9';
    $min_timestamp=strtotime('3 hours ago');
    $max_timestamp=strtotime('3 hours from now');

    //make sure the passed hash is legit
    if($_GET['hash']==md5($_GET['timestamp'].$key))
    {
      //make sure the timestamp falls within a reasonable amount of time
      if($_GET['timestamp'] >= $min_timestamp && $_GET['timestamp']< =$max_timestamp)
      {
        //output your data here
      }//end if
    }//end if
    ?>

    Of course, you can adjust the time window to your application’s needs as appropriate. If you need a client-side md5 library in JS…they exist out there. (i.e. I don’t know where one is at the top of my hat)

    Reply to this comment.
    13
  14. Avatarniels marsman

    I understand what you are saying, the only problem i have now is: how can i add more sites, every site is a single user and the application is only ristricted to their site. Now the problem with your code is that everyone could just copy and paste it in their website and use the script intended for someone else. The script is like a external login, you login in your website and then a admin page is loaded from another server where the user can manage some hosting/website updates for his site/hosting.

    Reply to this comment.
    14
  15. Avatarsteve-0

    Now the problem with your code is that everyone could just copy and paste it in their website and use the script intended for someone else.

    So that’s the point of the workaround, right (to take advantage of legal operations in a browser to allow you to load scripts from other sites dynamically)? If I understand you correctly, and you’re trying to restrict people from linking to your scripts from offsite (which is kinda not really on tt) in any surefire fashion; what you are looking for is something like a perl handler on mod_perl that serves the bodies of scripts for you. Then before the handler decides if it will write your script to the browser or write “Screw you hax0r”, you have access to the whole host of apache’s information — you can then always see the full URI for the script and filter accordingly.

    Oh also — kudos on this script too. =)

    Reply to this comment.
    15
  16. pingback pingback:
    GUJS - Grupo de Usuários Javascript » Arquivo » Ajax cross-domain com JSONP

    [...] Look Ma, Cross-Domain Scripting! [...]

    Reply to this comment.
    16
  17. pingback pingback:
    Read. « grahaNa 17
  18. AvatarBoyke

    Hi, is there any way to send post variables to the php (server side) script?

    Reply to this comment.
    18
  19. Avatarpoker net www online poker net

    In addition poker heads up online buy coffeehouse ring joint line four same day cash advance loan street seven corner deuces amount fold download giochi juice deck game round fill!

    Reply to this comment.
    19
  20. pingback pingback:
    jquery json remoting

    [...] JSON. ….. 1 - javascript pure cross-domain scripting 1 - ajax jquery json cross domains …http://borkweb.com/story/look-ma-cross-domain-scriptingSedna RSS jQuery.infojson parser doesn’t output - pedalpete Discuss jquery mailing-list … DWR for [...]

    Reply to this comment.
    20
  21. AvatarTracy

    I cannot seem to get your example working. Everything is error-free, but my callback function (bork) never gets visited. I’ve copy/pasted your client code exactly, changed the remote URL to this: http://www.twonkyvision.com/test.php (no that’s not a valid software license format), and made the first line in bork() to just send out a simple alert box. But my alert never gets visited, but no javascript errors showing up in my console.

    Am I missing something? My client box is MS IIS, but my server box is LAMP, would that be a problem?

    Thanks!!

    Reply to this comment.
    21

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Comment Preview:

 (4466) - cross-domain scripting (385) - cross domain scripting (165) - cross domain javascript (99) - json cross domain (94) - javascript cross domain (74) - cross domain JSON (34) - jquery cross domain ajax (29) - xmlhttprequest cross domain (28) - cross domain script (27) - jquery cross domain (27) - jquery ajax cross domain (23) - cross-domain javascript (23) - prototype cross domain (22) - javascript cross domain scripting (21) - javascript crossdomain (21) - cross domain ajax jquery (17) - cross domain (16) - JSON cross-domain (15) - access to restricted uri denied (15) - ajax cross domain (14) - javascript cross-domain (13) - allow cross domain scripting (11) - cross domain jquery (11) - jquery Access to restricted URI denied (10) - Access to restricted URI denied jquery (10) - firefox access to restricted URI denied (10) - firefox cross domain (9) - ajax cross domain jquery (9) - json (8) - xmlhttprequest (8) - crossdomain javascript (8) - php cross domain (8) - cross domain posting (8) - prototype cross site (8) - ajax cross domain scripting (7) - ajax crossdomain (7) - firefox cross domain scripting (7) - php include cross domain (7) - jquery load cross domain (7) - jquery ajax cross-domain (7) - cross domain prototype (7) - cross-domain JSON (7) - cross domain iframe resize (7) - Access to restricted URI denied XMLHttpRequest (7) - value (6) - javascript cross domain json (6) - cross domain post (6) - jquery cross domain post (6) - javascript Cross-domain scripting (6) - xmlhttprequest cross-domain (6) - jquery ajax crossdomain (6) - cross domain scripting ajax (6) - AJAX access to restricted URI denied (6) - javascript access to restricted uri denied (6) - RSS cross domain scripting (6) - cross domain XMLHttpRequest (5) - cross domain scripting json (5) - prototype cross domain ajax (5) - enable cross domain scripting (5) - php crossdomain (5) - ajax cross domain prototype (5) - ajax prototype cross domain (5) - ie cross domain scripting (5) - javascript prototype cross domain (5) - How to cross domain script (5) - javascript cross domain access (5) - cross domain scripting javascript (5) - jquery json cross domain (5) - jquery crossdomain ajax (5) - jquery cross-domain (5) - Access to restricted URI denied ajax (5) - xmlhttprequest Access to restricted URI denied (5) - access to restricted uri denied firefox (5) - json cross-browser Access to restricted URI denied (5) - remote (4) - cross-domain scripting with XMLHttpRequest (4) - cross domain ajax prototype (4) - crossdomain json (4) - JSON ajax cross domain (4) - cross domain php (4) - jquery crossdomain (4) - jquery cross domain xml (4) - javascript cross domain call (4) - jquery post cross domain (4) - jquery cross domain scripting (4) - xmlhttp cross domain (4) - disable cross-domain (4) - php load cross domain file (4) - iframe resize cross domain (4) - prototype ajax cross domain (4) - javascript cross domain php (4) - javascript cross domain access denied (4) - cross domain hack (4) - prototype Access to restricted URI denied (4) - access to restricted URI denied firefox 3 (4) - javascript cross domin script (4) - cross domain login (4) - xmlhttprequest crossdomain (3) - ajax across domains (3) - xmlhttprequest json cross domain (3) - json cross site (3) - cross domain ajax with prototype (3) - prototype cross-domain (3) - cross domain jquery ajax (3) - cross domain javascript call (3) - crossdomain firefox (3) - jquery cross domain iframe (3) - cross domain hash (3) - javascript cross domain hash (3) - crossdomain script (3) - look ma cross domain (3) - json cross scripting (3) - cross-domain jquery (3) - cross domain scripting XMLHttpRequest (3) - firefox cross-domain scripting (3) - script tag cross domain (3) - json jquery ajax cross domain (3) - allow javascript cross domain (3) - firefox 3 cross domain scripting (3) - javascript across domains (3) - AJS ajax cross domain access denied (3) - ajax cross domain hacks (3) - firefox 3 cross domain (3) - json dynamic script hack (3) - ie firefox javascript frame accross domains (3) - jquery cross domain script (3) - httprequest cross domain (3) - xmlhttprequest: enable data across domain (3) - cross domain java-script (3) - cross domain xhtml (3) - jquery ajax Access to restricted URI denied (3) - access to restricted URI denied json (3) - cross domain scripting iframe (3) - ie cross domain script (3) - jquery cross site json (3) - access to restricted URI denied dwr (3) - JSON cross domain script (3) - firefox XmlHttpRequest restricted URI denied (3) - jQuery.post cross domain (3) - firefox 3 access to restricted uri denied (3) - javascript cross domain posting (3) - cross domain httprequest (3) - javascript allow cross domain (3) - xmlhttprequest cross site image (3) - access to restricted URI denied javascript (3) - firefox javascript cross domain setting (3) - sending variables across domains in javascript (3) - cross domain scripting with json (3) - dynamically load cross domain external js (3) -