Yesterday I mentioned a proof of concept to try to stop script kiddies and data leechers from abusing server-side scripts that are intended to serve XMLHttpRequests (XHR or AJAX). Playing with URL or form parameters can get the server to return all sorts of data, sometimes even data that the developers didn’t intend you to have access to. The problem is that servers can’t tell the difference between a normal web page request and XHR.
Ray Camden blogged about how jQuery adds an extra HTTP header to help the server tell the difference, but headers are very easy to spoof.
My idea is for the server to issue the web page with an encrypted token. The token is the current date/time and must be sent back to the server for each and every XHR triggered by the current page. If the server doesn’t receive the token, or the token is invalid (i.e. it’s be tampered with) or the decrypted token reveals it’s older than, say, 5 minutes then the server returns a 404 error – page not found.
So, anyone who tries to submit data back to the server through dishonest means will find they get a 404 after 5 minutes. If they try to alter the token they get a 404 too. This will baffle script kiddies or hackers and hopefully they will move on to mess with someone else’s website. If they persist they will realise that they can’t generate their own encrypted token but will have to refresh the main web page every 5 minutes to obtain a new token and insert that into their script. That’s the only weakness in this concept, but taking it a step further you could log the IP from the first failed XHR and block serving that IP for the next 30 minutes. Or refuse to issue a new token within the same session or to the same IP.
As for genuine users you can set the web page to auto-fresh every 5 minutes. It will work best on sites where you don’t expect users to linger on the same page for too long, but of course you may prefer a longer token life (like 15 minutes).
Here’s a live demo – many thanks to Ray Camden for hosting it. The demo’s token will expire after just 90 seconds. The POST data is exposed in a grey area at the bottom of the page so you can tamper with the parameters to see what happens. The demo uses jQuery for XHR, of course.
I’ve commented the code so developers using PHP, .NET, RoR, etc can easily adapt the ColdFusion code. Download the demo code here.
If you improve upon it please let me know.
Oh, in case you’re wondering why I called it AJAXbouncer it’s because it offers a deterrent to potential trouble makers but doesn’t provide 100% safety – like bouncers standing outside pubs and clubs.