Gillius's Programming

Web Security: XSS and CSRF

At work I've been making a foray into web development. I've always been one to be very interested in "how to do it right" rather than just "get it done" and stop when it looks like it works. Security is one of the things where it works perfectly for the user -- but also for the attacker if you don't do it right. I've had a lot of experience with securing things with encryption, but the web is an entirely new (and scary) world.

The two attack vectors I looked into is XSS (Cross-site scripting) and CSRF (cross-site request forgery, aka XSRF).

I know this topic is covered in detail in other sites (more authoritative than mine), but I hope that this article helps provide another perspective or at least increases the awareness of these issues in the field.

Cross-Site Scripting

This exploit happens when someone can inject script code into your site. The primary way an application is vulnerable to this is when you provide unescaped code to a client that would be interpreted as HTML. An obvious way would be a forum post that allowed users to post a <script>. This script could steal information, the most important being the session cookie information and sending that to the attacker's site who can then "log in" as you.

OK, everyone knows to protect forum posts, of course. A good programmer protects any user-developed content on your site. But keep thinking -- one place you might not realize: The error handling pages. Everyone loves a good "404" page with a message "Oh, the URL ABC you tried to visit doesn't exist." Typically some web admin set that up once and no one thought about it again. Well, what if someone gets your user to visit (encoded of course) http://mysite.example.com/?<script>....? Now they have just injected a script into your site through your 404 page. What about a login page? "The user ABC doesn't exist". What about the user <script>bad_code();</script>? Does he exist?

There is plenty of more information on the Internet, and I'm not trying to outdo Wikipedia here, but here are some tips:

Another resource is this OpenAjax site page, which also covers CSRF.

Cross-Site Request Forgery

Learning about this really blew my mind, because I understood XSS but I didn't realize CSRF. CSRF occurs when an attacker causes an operation on your site. Even though the "request" came from the attacker's site, the browser will send the cookies (or HTTP authentication credentials) for your site to your site. This makes sense. Of course, the attacker can't see your cookies or see what you are doing on your site, but it might not matter.

In order to exploit a CSRF vulnerability, your application needs to have a request that performs an action beneficial to the user that is the same for all users. The typical example is the bank one, where visiting http://mybank.example.com/transfer?to=attacker@evil.com&amount=1234 will result in a money transfer. The attacker doesn't need the user's credentials nor does he even need to observe the request or response. That URL can be placed anywhere on the Internet easily, because most sites will let you publish content with images linked to any URL. Put that URL into the "img src" and the user will see a broken image but not know what happened. The link also needs to be put on a site that your visitors would visit as well, so of course large targets like Facebook and Google are far more likely targets.

OK, so HTTP "GET" requests with side-effects are bad style anyway. You can fix the img problem but not allowing this, but it doesn't fix the problem. If the evil (or compromised) site contains a hidden HTML form and javascript, it can perform a POST as well.

Unfortunately, to me it appears the browser cookie model and HTTP authentication models are broken in browsers, because they provide authentication information without prompting you. This makes sense otherwise every single page you click on would require the browser to ask you to confirm first. There's no way for a user to stop this except to always "log out" of your site and not view any other sites in that browser while logged in.

The solution is to foil the attacker by making it so that each user has a unique request that can only be generated by that user that does not involve solely the browser's cookie or HTTP authentication system. My understanding through reading is that any of the following ways to add user-specific data to the request would work:

You can also read more at Wikipedia.