290 likes | 456 Views
Cross-Site Ajax Challenges and Techniques for Building Rich Web 2.0 Mashups. Joseph Smarr Plaxo, Inc. joseph@plaxo.com. The promise of mashups. Create new experiences by combining components from different authors Each site focuses on what it does best
E N D
Cross-Site Ajax Challenges and Techniques for Building Rich Web 2.0 Mashups Joseph Smarr Plaxo, Inc. joseph@plaxo.com
The promise of mashups • Create new experiences by combining components from different authors • Each site focuses on what it does best • Can wire up components in a novel way • Google maps + Craigslist = HousingMaps • Rich interaction often requires talking back and forth between components • House’s address lat / long map it
Talking between web components • Normal situation: all on the same web site • Communicate across frames / iframes / popups • Talk to server using AJAX (XMLHttpRequest) • Problem: doesn’t work when components live at different domains (mashup situation) • Same-originpolicy • Can include JavaScript / images from another domain • Can’t talk to frame / iframe popup or send an XHR • Prevents snooping on secret web pages (e.g. intranet)
Image CSS JavaScript Domain B • So, how do mashups communicate? • CAN include image / JavaScript / CSS from Domain B • CAN send XMLHttpRequest to Domain A • CAN talk to other frames / iframes / popups on Domain A • CAN'T send XMLHttpRequest to Domain B • CAN'T talk to other frames / iframes / popups on Domain B XML / Web Page XHR • CAN talk to other pages on Domain A • CAN’T talk to any page on Domain A
How do mashups communicate? • Often, they don’t (Google maps 1.0) • Single JavaScript all processing done locally • Plotting lat/long or fetching image tiles is deterministic • Can’t get any additional data (e.g. geo-coding) • Server-side proxy (HousingMaps, Flickr) • Talk to your server it talks to the foreign site • Problem: bottleneck; barrier to mass deployment
Server-side proxy Server Domain A Server Domain B Web Page Domain A
How do mashups communicate? • Often, they don’t (Google maps 1.0) • Single JavaScript all processing done locally • Plotting lat/long or fetching image tiles is deterministic • Can’t get any additional data (e.g. geo-coding) • Server-side proxy (HousingMaps, Flickr) • Talk to your server it talks to the foreign site • Problem: bottleneck; barrier to mass deployment • Use flash for cross-domain communication • Can use crossdomain.xml to allow foreign sites • Yahoo maps uses this to do geo-coding
Flash proxy Server Domain B crossdomain.xml Web Page Domain A Flash
How do mashups communicate? • JSON-P (Script injection + callback) • Dynamically load JavaScript file with data • Use DHTML to inject a <script> tag in the document • Data is returned in JSON (JavaScript data format) • Clever trick: specify callback function on URL • foreign-site.com/json-api.js?callback=myFunc • Loads myFunc({ data: “hello” }); round-trip! • Works well in practice, but some drawbacks • Limited control vs. XHR (just loads or doesn’t) • API provider can return malicious code (e.g. steal cookies)
JSON-P Server Domain B JSON + callback Web Page Domain A <script>
Using JSON-P in OO web apps • Problem: callback function has to be global • Complex code maintains state / instances • Would like to handle callback with instance function on instantiated object • Solution: bind the callback dynamically • Create a globally-unique function name • Usually global prefix + auto-incremented counter • Use a closure to call your function in object-scope • Send the global function name as callback it calls your scoped function
Dynamically binding a global callback var cbName = 'cb' + JSON.callbackCounter++; var cbFunc = function(jsonData) { myFunc.call(myObj, jsonData); // call bound callback }; JSON.callbacks[cbName] = cbFunc; var globalCallbackName = ‘JSON.callbacks.’ + cbName // url: '/json-api.js?callback=' + globalCallbackName; • Used by dojo (ScriptSrcIO), Google Maps 2.5, Plaxo, etc.
Summary of cross-site techniques so far • No cross-site communication • Include partner’s JS file once (can’t talk again) • Server-side proxy • Talk on the backend (bottleneck, barrier to adoption) • Flash proxy • Talk through cross-domain flash (requires flash) • JSON-P • Talk through script-injection with callback (less control, partner could be malicious)
What about updating another web page? • Proxies / JSON-P let you access foreign data • But still can’t touch a foreign frame/iframe/popup • Many potential mashups would like to interact with existing web pages • Auto-fill a form with your contact info • Highlight relevant search results / text snippets • How can two sites that want to cooperate get around the same-origin policy?
What does the partner site have to do? • Add the button to your page <a onclick="showPlaxoABChooser('textarea', '/cb.html'); return false" href="#"> <img src="http://www.plaxo.com/images/abc/buttons/add_button.gif" alt="Add from my address book" /></a> • Specify the ID of your e-mail <textarea> • Specify the location of your hidden callback page • Add a small callback page on your site <html><head><script type="text/javascript" src="https://www.plaxo.com/ab_chooser/abc_comm.jsdyn"></script></head><body></body></html> • Full instructions and demo: http://www.plaxo.com/api
What does Plaxo have to do? • Remember: Plaxo filled in a textarea on zazzle! • Need to get around same-origin policy • Without server-side proxy (JS/HTML only) • JSON-P won’t solve this problem • Widget popup is hosted by Plaxo and goes thru several steps • Zazzle doesn’t know when to request the contact data • Solution: “The JavaScript Wormhole” • Add hidden callback page on zazzle that includes Plaxo script • Plaxo popup loads callback in an iframe when done • Script is dynamically generated, and includes selected data • IFrame is also on zazzle (and has the data), so it can tell parent.opener to fill in the textfield
zazzle.com/email_this plaxo.com/ab_chooser plaxo.com/ab_chooser Iframe: zazzle.com/cb.html Script: plaxo.com/ab_chooser/abc_comm.jsdyn
Who’s using the Plaxo widget? • See more at http://www.plaxo.com/api/gallery • Using the widget? Let us know!
Generalizing the JavaScript Wormhole • Site has a generic callback page to give you access • Site tells you the location of their callback page • Callback page loads your domain’s JavaScript • JavaScript is dynamically generated to include your data • Can pass script url with query args to callback page • /cb.html?http://foreign-site.com/json-api.js?name=val • Access query string on cb page with location.search • Site can restrict callback page to trusted hosts • Only load script if it’s on a trusted domain • Could further restrict to certain URL prefixes, etc.
<html><head><title>Generalized JavaScript Wormhole</title> <script type="text/javascript"> var trustedDomains = [ "http://www.plaxo.com/api/", "http://www.google.com/" ]; function isTrustedDomain(url) { for (var i = 0; i < trustedDomains.length; i++) if (url.indexOf(trustedDomains[i]) == 0) return true; return false; } function doWormhole() { var url = location.search.substr(1); // chop off ? if (isTrustedDomain(url)) { var script = document.createElement('script'); script.type = "text/javascript"; script.src = url; document.getElementsByTagName("head")[0].appendChild(script); } else alert("ignoring untrusted url: " + url); } </script></head><body onload="doWormhole()"></body></html>
Where do we go from here? • Ajax is a “hack” on top of an old platform • The platform can evolve
Where do we go from here? • Ajax is a “hack” on top of an old platform • The platform is evolving
Where do we go from here? • Ajax is a “hack” on top of an old platform • The platform is evolving • What platform do we want to build?
Should we open cross-domain XHR? • After all, we can already include foreign JavaScript, image, and CSS files • So why not XML too? (“just another resource file”) • HTML looks like XML (esp. XHTML) • Hard to make sure you really meant to serve that page as XML data (cf. js / img / css) • Personal / private info more often in XML / HTML • But increasingly a problem with JS too (JSON) • Cookies / creds sent with XHR request • Can’t easily distinguish direct vs. XHR access
Trust relationships between sites • Random site accessing this file vs. trusted partner • Flash does this with crossdomain.xml • Web services do this with certs / IP whitelists • JavaScript wormhole does it (sort of) • Should a trust relationship exist for mashups? • Want to minimize barriers to adoption / innovation • When sharing user info, should have prior agreement? • How formal / technical should this trust be?
Proposals for better cross-site tools • ContextAgnosticXmlHttpRequest (Chris Holland) • Alternative to normal XmlHttpRequest for cross-site • Don’t send/receive any cookie or HTTP auth info • Server must specify X-Allow-Foreign-Hosts in response • JSONRequest (Douglas Crockford) • New browser object for cross-site JSON (like XHR) • Allows GET / POST / cancel of JSON request / response • No cookies / auth info sent or received • Requires special headers in request / response
In conclusion… • Cross-site communication is tricky but important • Key enabling technology for building rich mashups • Raises legitimate security issues that can’t be ignored • Today: Use server-side proxy or JSON-P • Proxy introduces bottleneck, but provides full access • JSON-P is more scalable, but limited to JSON APIs • JavaScript Wormhole lets you touch foreign pages • Keep the discussion of better tools / protocols going! • This problem is here to stay • Browser developers are listening!
For further reading… • Cross-site limitations • http://getahead.ltd.uk/ajax/cross-domain-xhr • http://msdn.microsoft.com/library/default.asp?url=/workshop/author/om/xframe_scripting_security.asp • FlashXMLHttpRequest • http://blog.monstuff.com/FlashXMLHttpRequest • ContextAgnosticXMLHttpRequest • http://chrisholland.blogspot.com/2005/03/contextagnosticxmlhttprequest-informal.html • JSONRequest • http://json.org/JSONRequest.html