Cross Site Scripting: what it is, and how to prevent it

Just think: you just created a browsergame. It’s taking off, and people are signing up by the truckload.

You’ve carefully made absolutely sure not to fall victim to SQL Injection, and your launch is going well.

But suddenly, something goes wrong. All of a sudden, users visiting the homepage are automatically getting redirected to nefariouswebsite.com!

What happened?

You’ve just become a victim of what’s known as a Cross Site Scripting attack(or XSS for short). Basically, a user enters some sort of malicious code(like some Javascript) into any area where user-input data will be displayed. It could be as simple as this:

<script type='text/javascript'>
window.location.href='http://google.com';
</script>

And the moment that that content gets displayed back to a user, their browser will see the <script> block and then redirect them. In this case, they would only be going to Google – but it’s easy enough to change the URL a user is getting redirected to to anything that you want.

How can you protect against this, if it’s a vulnerability that occurs in any situation where user-input data is displayed?

It’s actually a lot easier than you might have thought. All you need to do is escape all user input that will be displayed. And that means everything.

Do you display the user’s username anywhere? Even if it’s only ever displayed on that specific user’s profile page, you still need to escape it. Even if it’s only ever displayed to the user themselves.

Thankfully, PHP has a function custom-built to handle this – htmlentities(). Perl has a module that you can use to accomplish the same thing – HTML::Entities.

Now, you might be saying “that’s all fine and dandy, but what do I care? It doesn’t affect me if some users are getting redirected from some random page, deep within my site” – but there are multiple problems with that logic:

  • Attacks breed more attacks

    Because it’s worked once, an attacker knows it will work again. So there’s no reason not to do it again – and not to do it in a more public place. Attackers perpetrating XSS attacks against sites will sometimes ‘practice’ in a quieter area of the site, so that the site administrators do not become aware of the exploit until it’s too late.

  • User frustration = no more users

    Let’s say an XSS attack is executed against your site, and before you can fix it over 1000 users are redirected to nefariouswebsite.com – which just so happens to contain a malicious virus. That’s 1000 users who are never coming back and will never recommend your game ever again. And if you’re unlucky enough, there might be 25 among those 1000 that have decided it’s your fault for not securing your site adequately, and sue you.

Really, there are no gains to be made by not securing your game against XSS attacks. And it’s easy to implement – just make sure htmlentities() (or its equivalent, in your language of choice) is being called on any and all data you retrieve and display.

As long as you escape any and all data that you are going to be displaying to the user, you can avoid the risk of falling prey to an XSS attack. And no matter whether your browsergame is just getting started or already established, that’s always a good thing.

Wish there was more?

I'm considering writing an ebook - click here.

.

Luke is the primary editor of Building Browsergames, and has written a large portion of the articles that you read here. He generally has no idea what to say when asked to write about himself in the third person.

Monday, April 28th, 2008 design, security
  • Roy

    So why not simply do both? Make Account names viable if they are only Numbers and letters( ex A-Z, a-z, 0-9), no other char allowed, as well as escaping the repeating information?

  • Roy,
    You could definitely do both - how much you allow or disallow is entirely up
    to you.

  • Abraxas

    I agree that as a general rule this is excellent practice but for something like the user name wouldn't it make for sense to escape it before adding it to the database instead of every time it is displayed? In fact as part of my registration validation I compare the user name with the return from the escape function and if they're not equal I reject the name:

    if ($username != htmlspecialchars($username)) {
    $err = "name contains invalid characters";
    }

  • While it would make sense to escape the username before it enters the
    database, escaping it afterwards helps protect you against XSS attacks that
    originate *from* your database - for example, if an attacker gained access
    to your database and hand-entered the data.
    Rejecting usernames that have special characters in them isn't a bad idea,
    but it tends to confuse the user - which characters are invalid? Which
    aren't? It would be more useful if you could tell them which characters were
    not allowed.

  • me

    I'd say that if someone has accessed your database and hand entered the data you have bigger problems than XSS attacks. Escaping before inputting into the database means you only need to escape once which makes things more efficient. Also use htmlspecialchars not htmlentities it does the same job but uses less resources.

blog comments powered by Disqus

About

Building Browsergames is a blog about browsergames(also known as PBBG's). It's geared towards the beginner to intermediate developer who has an interest in building their own browsergame.

Sponsors

Got Something to Say?

Send an e-mail to luke@buildingbrowsergames.com, or get in touch through Twitter at http://twitter.com/bbrowsergames