Improving website security
Posted by Steve on Wed 22 Nov 2006 at 08:31
Recently this site was updated to avoid a potential security weakness. This article briefly describes the problem which was fixed, and explains some of the most common online security problems.Introduction
The hole described was new to me and I think it is worth sharing in the interests of full-disclosure, credit to Daniel Gillmor, and hopefully the securing of more sites.
Many web-developers (although not all!) are familiar with Cross Site Scripting attacks, often known as XSS, which are usually the result of not filtering input to applications.
A standard example would be a message-board, or forum, which allowed users to login and post messages which would be displayed literally - so a malicious user could create a message reading:<script>alert(1);</script>
The root cause of these security issues is trust. The implementor of the forum or message board trusted the users input and didn't sanitize it appropriately.
The XSS attacks exploit that weakness to steal cookies, etc.
(Once upon a time I wrote a simple online XSS demonstration/explaination, which might make this abstract discussion more interesting or obvious.)
SQL injection is a problem specific to database-driven websites, especially those written in a hurry without the use of the appropriate language features.
Essentially SQL injections arise because input is passed directly to a database query without being escaped, or processed, correctly.
This is virtually identical to the XSS attack described above, just a different level of attack. (The remote-database rather than the local-client browser.)
Thankfully most programming languages and libraries which have database support make use of "binding" and other mechanisms which should make these issues trivial to prevent. The sad fact is that many programmers don't use them.
"Cross Site Request Forging" is the new name for a new problem, or one new to me at least.
The root cause of the CSRF attacks is also trust. The trust of a website by a user of that site. This trust is exhibited by the fact that the user never, or only rarely, logs out.
In a typical scenario the communications between a webserver and client browser looks like this:
- Client makes a request to the server.
- The server responds.
- The client displays/uses the response.
For example to create a new weblog entry the user would browse to this site, click upon the "add entry" link in the sidebar and submit the resulting form.
Now consider what happens if a malicious external site were to copy the "add weblog entry" form and host it upon their site.
They could change the wording, hide the fields, etc. But ultimately there is nothing stopping them from hosting a modified version of the form - and serving it to users.
This is where the cross-site issue comes into play. If that remote site can coerce, persuade, or trick a user logged into this site to submit the form then the request will be processed by this site using their cached credentials.
Because they trust this site, and have remained logged in, the submission would be processed and the unsuspecting user would have a new weblog entry posted which they didn't explicitly write, or expect. For example "I like cheese."
Step by step the attack works like this:
- External site copies a form from this one.
- External site persuades/cajoles/tricks a user who remains logged in here to visit their site and submit the form.
- The server here receives the form submission and proceses it
- Because it doesn't realise the form came from a malicious remote source.
- And because the user was logged in any authentication tests succeed.
- The user now arrives at this site with new content posted in their name.
The solution to this problem is potentially invasive but conceptually simple. Rather than serving forms to clients and then processing them without regard to the submission source the forms each include a "session token".
When a form is submitted this token is examined, and if it matches the token which was sent with the form the processing occurs, if it doesnt an alert is raised.
This utterly prevents the attack because it means that the malicious remote server cannot serve a valid form - it can't predict the secret form session token, so the submission will always fail.
(There are simpler solutions involving the use of the HTTP Referer (sic) header, but these are unreliable as this information might be forged or not present.)
It is worth noting that many sites fail to verify the submission of forms in this manner, so they are potentially at risk of malicious (ab)use of their forms.
With this discussion in mind I will now describe three changes I've made to this site:
- Cookie Safety
Microsoft's Internet Explorer supports an extension to cookies called "httponly". The intention of this support is that the cookies served by a site will be marked as unavailable for scripting use.
This means that if there were an XSS attack available in this site then users of that browser wouldn't be vulnerable to cookie/session theft.
A bug was filed against Mozilla, but progress appears to have stalled (#178993).
I'm unaware of any XSS attacks lurking in the current codebase, so this is a small paranoia addition rather than a significant change.
(IE comprises about 9% of visitors to this site, certainly not the majority. However the change involved is sufficiently minimal that it is worth doing just to mitigate any future attacks.)
- Session Safety
On a similar front it is now possible to choose a "secure" login when you visit this site. This actually ties your login session to your IP address.
Again this offers no increased security in the normal course of events, but if there were ever to be a security issue which resulted in a cookie or session theft due to XSS, or similar, then you would be protected if you chose this option.
There is a brief guide to this facility linked to from the login form.
- Cross-Site Request Forgery Protection
This change is the most significant and is the one which caused me the most pain - as discussed above there is a potential weakness in the handling of many form submissions in online applications.
In the case of this current codebase I now insert a "session token" in each significant form, which will prevent the processing of rogue submissions rather than end-user page views.
This is a significant change, which appears to be working nicely, but as I'm all too aware there may be bugs. If you find them please do report them, either via mail or a site message.
I hope that was interesting reading both for regular visitors to this site, and for any potential web-application programmers.
If you'd like to disclose any security issues relating to this site I'm always prepared to listen and work with you. If you'd like to donate an SSL certificate for real secure logins that'd be a nice suprise too ;)