02.Cross-site Scripting (XSS)

In this tutorial I will explain what Cross-site scripting (XSS) is. I will then develop a basic article application with a commenting system that is vulnerable to an XSS attack in order to demonstrate how to carry it out, and how to effectively prevent against this critical security threat using PHP.
Transcript:
Hi there I’m Abdi Gulaid an experienced freelance web developer at BestCoder.co.uk. I've put this video together in order to explain demonstrate, and show you how to prevent against XSS attacks when developing websites for the web. If you are an experienced or a novice web developer and want to learn how to make your clients websites more secure then this video tutorial is for you.
This video will be as clear and as concise as possible in order to help you learn. In this tutorial I will explain what an XSS attack is. I'll then quickly hand code a dummy PHP application that we'll use as a test bed to demonstrate an XSS attack. Once we do this we'll then go through the steps in how to prevent against an XSS attack.
So what is XSS you ask?
XSS is short for Cross-site scripting. XSS is a security vulnerability that is found in poorly developed web applications that allow for malicious attackers to inject client side scripts such as JavaScript within actual web pages. XSS attacks are common and account for nearly three quarters of all website attacks in 2007 according to statistics published by Symantec.
XSS attacks have been around since the dawn of the web, and large web companies haven't been immune to XSS attacks. Companies that have been hit include but are not limited to: Google, Yahoo, Facebook, and Twitter.
Preventing against XSS attacks for your clients is critical during the web development process and it’s the first and most likely attack a hacker will attempt to carry out on a website. Good web developers understand the importance of this. To demonstrate XSS I’m now going to develop a small web application. It will be a simple article web page that allows for people to leave comments, I'll write it in PHP as it's the most common web language, and we'll use MySQL as the database to store the comments.
Right our basic PHP application is now complete. Before I demonstrate how an XSS attack works and how you can prevent against one let me explain the two types of XSS attacks. XSS attacks come in two variants: there's the non persistent type, this is the most common variant. The XSS code is injected directly into the website's URL, an attacker will have to explicitly get someone to use the compromised URL in order to carry out this attack. Hackers typically distribute the URL via email or other method in order to carry this attack.
Then there is the persistent variant, this is less common but far more dangerous. The code is injected permanently injected into the webpage, which is then repeatedly served to all visitors of that webpage.
Ok, now let’s demonstrate a non persistent XSS attack. As mentioned a moment ago, non persistent XSS attacks usually involve injecting code within the website's URL, I've made our dummy application deliberately vulnerable to this type of attack in order to show you how it’s done. To demonstrate this we'll inject a simple JavaScript alert into the website URL, our app uses the GET method to receive data stored in the URL, and anything after the equals sign will be written into the page by our PHP script. We'll deliberately write our JavaScript alert after the equals sign.
I'll now visit this compromised link, our JavaScript alert should execute as soon as the page loads. As you can see the JavaScript that we've placed in the URL has been executed, this is a successful non persistent XSS attack. A simple alert won't do much harm but an attacker will typically inject code that will download an external script that will do far more damage. These larger payloads can be programmed to steal cookie information and even personal information stored on the website. As this is a non persistent XSS attack, an attacker will have to distribute the actual URL and get someone to visit the compromised link in order to initiate an attack.
Ok, that's the non persistent attack type demonstrated. Now let's demonstrate the persistent attack variant. I've made our application susceptible to this in the comments section; again we'll simply inject a JavaScript alert into our comment in order to demonstrate the attack.
As you can see our script has been executed, and we can now see the alert. This attack type is different in that the script has been permanently stored in the database, and this script will execute every time this page is visited for as long as the script remains in the database. Again a simple JavaScript alert is harmless, but an attacker will typically inject code that will download a larger external script, that will cause far more damage.
That’s the two attack types demonstrated; now let’s look at the ways in which we can prevent against them. Always validate user input and never trust user submitted data, if you are expecting numbers, validate for number only in your code and reject data that doesn't conform to the expected data type. Secondly, always sanitise user input before storing the data in a database and always sanitise GET variables before carrying out a query or displaying the search term for instance.
I'll now demonstrate how to do this in our dummy app, the GET URL variable is currently displayed without any sanitisation, and any code that is injected will be executed by the web browser. We've already seen how dangerous this can be, fortunately PHP has a few built in functions that can be used to sanitise data, and HTMLENTITIES is one of those functions. We'll use this function to convert all submitted special characters to their HTML equivalents. We'll encapsulate our GET URL variable within a HTML entities function in order to do this. That’s now done; let’s now test the page again in order to see if the JavaScript code has been sanitised. Great as you can see the XSS attack has failed we have successfully sanitised the URL injection. Let’s view the source code to see how this has been done; we can now see that nearly all of the injected special characters have been converted into their HTML equivalents as a result this script will fail to load.
Ok, now let’s demonstrate how to prevent against the persistent attack type in our comments section. As you can see, our PHP code for storing the comments has no sanitisation whatsoever, we'll simple enclose both the name and the comments variable within the built in HTML entities function in order to sanitise the data before it gets stored in the database. Ok that's now done so let’s check to see if we can carry out an XSS attack within our comments section. As you can see the XSS attack has not been executed and the injected code has in fact been sanitised.
Let’s view the source code to see the sanitised comment; the HTMLENTITIES function has converted nearly all of the injected special characters into their HTML equivalents. This is exactly what we wanted, as a result our attempted XSS attack has failed to execute.
That's XSS explained and demonstrate you should now know how to carry out and prevent against XSS in order to make your clients websites more secure. Thanks for watching and if you like my videos don't forget to subscribe.
Erhan Karadeniz
Another great tutorial from you Abdi. Seriously I cannot thank you enough for what you are doing, I am learning so much from you and im enjoying your tutorials they are both fun and engaging, whilst remaining easy to understand. How would you go about securing applications that are written in ASP?
Count me in as a subscriber!
Jay Tillery
I know about XSS, but the background/supporting information you provided I didn't know about I guess you learn something new everyday. ASP is something I would love to learn about so. Maybe you should get us all to vote on what we want to learn, that way you can create tutorials that are the most in demand.
Andy Sowards
I'm glad you did this, I asked for a tutorial on XSS and you delivered. First class just as expected.
My question is doesn't PHP have an automatic way of preventing against XSS? SQL injection has magic quotes and wouldve thought theyd have something for XSS.
Daniel Licht
Thanks for this excellent video tutorial. I had heard about these attacks, but it was quite vague to me, and I had no idea how easy it was. Just underlines the importance of data validation on web forms. Thanks for the eye opener!
BTW. Your site has some pretty informative video tutorials. Keep up the good work. I’ll drop by from time to time.
Umatun
White list input filtering is recommended in order to avoid cross site scripting.Every php developer should never trust the user provided data even if it is from cookie, drop down list or hidden form fields.
We should always check the script tag in user input data too which is more dangerous in this context.
Rob Burns
Hi Abdi, very gud job, keep it up!
Kirsten Winkler
Abdi is totally right.
Do not completely trust Web sites that use HTTPS (Secure Sockets Layer) when it comes to XSS; HTTPS ensures secure connections, but processing of the data entered by the user is internal to the application. If the application has XSS holes, the attacker may send a malicious script that can still be executed by the application and lead to XSS intrusions.
Be3d
I have done pretty well to prevent XSS Insertions by not allowing HTML to be entered in edtible text areas. However, what if somebody has the following situation. Let's say you wanted to give users a way to enter a URL in an input form. This URL could be a previous employer's website, education institution, or even a portfolio?
Japman Bajaj
@Be3d - There are many things you can do to prevent XSS. However, the general rule of thumb is that XSS prevention an "output thing" not an "input thing."
In your example above, the first thing I would use a regular expression to first validate the URL. Whether you do that in JavaScript, PHP, or some other server side language, thats the first thing you should do. All domain names have a specific format with only certain letters that are allowed. Checking this should be good enough.
Tami Reiss
Couldnt' get my head around this subject, but this video was just the medicine I needed
Keep up the good work!
Nikki Backshall
I watched your XML tutorial a while back, and this has totally hit the subject on the nail. You are brilliant and learning from you is so easy, looking forward to the next. :)
Anton Davis
How long have you been a programmer? you are so knowledgeable and would love to know how you got to where you are. Thanks
Timothy Sykes
Jeez you type fast!! slow down sometime as I cant keep up.
Tony Ruiz
Have just begun learning PHP and someone shared this video with me. I now have XSS covered. Thanks for sharing.
Michael Locke
Hi Abdi
The htmlspecialchars will still execute the HTML? for example if you have Hello in bold Will Hello still appear bold? thanks
David Spinks
Hey Guys, the security studies is coming along great.
I have a quick question though. How do you validate whether a URL exists?
Michael Gioia
Escaping is the way to go. It's how it should be done if you just want to display text on a page, and in such case it's 100% safe (and if your encoding is ok, then XML well-formed as well).
Filtering based on whitelist is good too, but under assumption that you wanted to display formatted HTML, not text. It's much more work (and CPU time) too. It's not suitable for attribute values.
Grant
Cool post, but shouldn't XSS security be done via a very restrictive *whitelist* approach? I mean you can only escape so much, but in the end, there is going to be a way unless you reconstruct the DOM based on elements from input you know are safe.
HTML Purifier seems to do this the best.
Ryan Wiseman
Great tutorial Abdi. Thank you
Joris Lucus
Nice post, basically like another injection method and reminds me of SQL injection. And preventing one is a simple case of rewriting the URL. I'll try to another language, ) :)
Saad Shamim
I was thinking about a something like HTML Tidy. Anyway, I don't have any experience using a HTML purifier, but I don't think restricting or filtering HTML is that easy - at least not in our web world where 90%+ of the HTML written is garbage and most sites include inline CSS and JavaScript and most sites use onclick and other event handlers.