Why you shouldn’t rely on ajax’s same origin policy

XmlHttpRequests (or “ajax“) is generally considered to be safe because it is restricted by the “same origin” policy, but that isn’t entirely correct. Consider the following: an ajax-call, like all http communication, consists of a request and a response. For read-operations the response is needed, for write-operations … that ain’t necessarily so!
So how can a “hacker” send a request for such a write-operation and have it executed (which amounts to  “cross site request forgery” actually)? There’s a number of  possibilities:

  1. Execute a GET-request by including it in the attack-site html as the src of a script, css or img tag, for all of which the same origin-policy does not apply.
  2. Using JavaScript to create a form, populate it and POST it, the same-origin policy does not apply to forms being posted.
  3. Just do a normal XHR-request, the same-origin policy applies, but some top-notch browsers will execute the request and just ignore the response (is that a bug or a feature?)

Conclusion: if you want to do anything more than read-requests on the same domain, you really-really-really have to protect your resources against CSRF using one of the techniques that are described in this wonderful OWASP CSRF cheat-sheet.

Web API security basics

When I proposed the lead developer of an open source web application to enable JSONP for the API, the developer replied:

The whole thing sounds easy enough to implement, but I have some doubts that it will open the project to XSS attack of some sort. Don’t really know why, though. 🙂

We mailed a bit more about the risks of cross site scripting and then he wrote the following:

Sadly we can have malicious JS problems since cleaning up of incoming data is optional.

For an unrelated project I asked about authentication for a write-operation in the API and the reply was:

Authentication is not in the API yet. Currently you must include a session cookie along with API requests to perform a write, but the cookie itself is the one you get from logging in [in the web front end] as you would normally.

Which sounds a lot like “we support cross site request forgery out of the box” …
As with normal web applications, web API-security is an important (but complex) issue, which is not always easy to grasp. Based on a basic understanding of things, the following guidelines can go a long way into securing things both on the API-side and the client:

  1. Know who you’re dealing with; disable API-access for your users by default (allowing them to opt-in), provide bullet-proof authentication and session management in the API and throw in a synchronizer token to prevent cross site request forgery
  2. Never trust input from users or external systems; decide what to trust and filter out everything that’s not in that white-list (SQL-code, server-side code, javascript, and even html and css)

If you apply these basic principles to JSONP (make sure to filter the callback-parameter and set the correct content-type in your response) you’ll have a whole lot less to worry about!
More info:

No more jsonp for Google geocoding webservice?

I needed to do some reverse geocoding in a javascript webapp. The Google Maps API worked flawlessly, but it seemed overkill to load all that javascript just to do one lousy reverse geocoding lookup (esp. on a mobile device, my target platform).  I searched some more and found the Google geocoding webservice, which is invoked with a simple HTTP GET request and returns the response in JSON. Version 2 of this service works great, as you can specify a callback-function to do jsonp (a simple method to allow for cross domain ajax requests),
This example request for v2, http://maps.google.com/maps/geo?q=51,4&sensor=false&output=json&callback=parseme, results in a response containing a call to your own “parseme”-function, with the json-object as the payload;

parseme && parseme( {
"name": "51,4",
"Status": {
"code": 200,
"request": "geocode"
},
"Placemark": [ {
"id": "p1",
"address": "Brukkelen 191, 9200 Dendermonde, Belgium",
...
]})

But a month ago Google announced a new version of their geocoding webservice and the documentation for V2 mentioned that it was deprecated in favor of the Geocoding V3 Web Service. so I switched to the new API, only to discover that callbacks aren’t supported any more.
An example request for v3 http://maps.google.com/maps/api/geocode/json?latlng=51,4&sensor=false&callback=parseme results in nothing but the javascript-object:

{
"status": "OK",
"results": [ {
"types": [ "street_address" ],
"formatted_address": "Brukkelen 191, 9200 Dendermonde, Belgium",
...
]})

And that, my dear fellow travellers, sucks big time. JSON without the P means we’re back to useless proxy-scripts on our servers. So until Google lets Jason pee (sorry folks, I just had to write this) in the V3 geocoding webservice, I’ll continue using the deprecated V2 with sweet -but undocumented- callback!

Over internet en development, en waarom ik er zo goed in ben!

Het is toch straf dat de web-bozo’s van één van Europa’s grootste IT-services bedrijven weer eens moeten toegeven dat guru Goossens toch gelijk heeft?

“Jaja, cross-domain Ajax dat kan, de nieuwe DWR maakt dat immers
allemaal perfect mogelijk.”

Toen ze me dat een paar maand geleden antwoordden, lachte ik minzaam en besloot rustig af te wachten. Want als ze mijn recept niet moeten, dan lijden ze maar honger. ‘t Is toch waar zeker? Want ik wist dat ze vroeg of laat toch tot het besef zouden komen dat dat inderdaad niet werkt. Security warnings all over the place. En dan “Het ligt aan de browsers” roepen, ja, tarara!
Het is alleen spijtig dat ze pas enkele dagen voor de release tot die conclusie komen, het zou de multinational in kwestie heel wat geld en kopzorgen bewaard hebben als ze vroeger naar mijn onbetaalbaar advies hadden geluisterd.
Enne, als voetnoot; met een iframe gaan klooien is écht geen proper alternatief jongens!
(Met dank aan meester- marketeer entertainer Steven Feys)