Cross and bothered
If you manage websites you’re probably aware of increasing attacks of the type called Cross-Site-Scripting or XSS, to which many high-profile sites and commercial products have been vulnerable (see www.xssed.com and lose sleep!). XSS attacks come in a variety of forms, but let’s look at a very simple type: my examples are in ASP, but all other web languages are vulnerable because it isn’t a weakness of the language or operating system but of your code. Yes, this one is your fault! An XSS attack involves changing the URL of a web page being called and embedding a script into it. Imagine a web page that displays items from a database, called “showitems.asp”, which needs to know which item to display and so takes a parameter called “id” which is the item number to display. The URL would look something like www.yoursite.com/showitems.asp?id=1234. Let’s keep things simple and assume we display this item on the web page, using code like:
<% response.write(request.querystring(“id”)) %>
Now imagine that someone modifies the calling URL to www.yoursite.com/showitems.asp?id=script>alert(“Hello World”)/script>
What happens now is that our code will insert:
<script>alert(“Hello World”)/script> into the HTML source of our page instead of the id 1234. The browser will render this code and pop up a dialog box with “Hello World” in it. If this happens, then that web page is susceptible to XSS attack. You may be thinking a popup is no big threat, but consider what’s actually happened: someone executed unauthorised code in your web page, and the possibilities for mischief go way beyond “Hello World!”. I have no intention of describing how to launch an attack – but trust me, it can be done. If you have access to the log files from your web server then examining them will reveal such attempts. And don’t think that because you don’t use a database that you’re exempt – any page that displays information from a previous page could be vulnerable.
The way to stop these attacks is always to test the data that you read from the previous page: not just data contained in the URL, but also any cookies since these could be hijacked from a previous page in an XSS attack. So if your code only expects a numerical value then only let numbers pass; if you’re expecting a string then examine it, perhaps check its length and discard anything else, or remove any characters that shouldn’t be there. For example, the characters < and > could be removed, as could “;” which is often used in SQL injection attacks as is the ‘ character. Given that these characters are so potentially dangerous and can be removed with no effect on the running of the site, why doesn’t the programming language, or perhaps the web server, block them by default? I have no answer.
For users with IIS6, I’ve found a good add-on that will stop SQL injection attacks, saving you from having to go through a website checking for vulnerable code. It’s available at www.codeplex.com/IIS6SQLInjection and works as an ISAPI filter, and the source code is available. I used it on the site of a client that was being attacked and it solved the problem quickly, giving the programmers time to fix their code just in case.
The easiest way of correcting your site if it appears to be vulnerable to XSS attacks is to write a function that will remove the danger characters. To keep it easy to manage, probably the best way is to create a file containing a function that can be called from your code, then set your pages to include this file using the code: