In Depth #3: Escaping Output Safely
Cross-Site Scripting (XSS) is a major concern - if someone can run their own code in your users browsers, they can do whatever they like...
I said this a few times in the last security tip, but it’s worth repeating here:
Don’t trust user input. Don’t trust user input. Don’t trust user input.
But why?
Users can be crafty and sneaky1, and if they have malicious intent, they can come up with all sorts of creative and unusual ways to subvert the behaviour of your applications intentionally. Our job as developers is to build a system that prevents these sneaky users from doing things that we don’t want them to do, while still allowing them to do everything we do want them to do.
What is Cross-Site Scripting?
A common trick that sneaky users (i.e. hackers) love to do is inject their own javascript into websites, and then trick other users into executing that javascript. Because, as an attacker, if you can get your javascript running in a victim’s browser, it gives you full control of their browser. This is known as Cross-Site Scripting, or XSS, and it is usually the result of not escaping user output safely.
Cross-Site Scripting (XSS) comes in two flavours: Stored and Reflected. They both have the same result - the attacker injects javascript into the page through unescaped output - but they differ in how the javascript gets onto the page and where it is stored.
Let’s take a look at both:
Stored XSS
Stored XSS is where the payload (javascript) is stored and later retrieved to be included on a page. This would usually be a field stored in the database, which is loaded every time someone tries to view the record from the database.
A common scenario for stored XSS is a comment field on a post. The hacker injects a malicious script into a comment, which is stored in the database. Then when someone on the admin side tries to view the comments, the javascript executes in their browser and does something the admin didn’t intend - often without their knowledge too!