Posted January 18, 2013 by Spyros in PHP Programming

Introduction to PHP Security


When it comes to PHP, some 99% of amateur sites and 60-70% of all sites use the professional scripting language called PHP. But is it safe to use PHP? Does the implementation of the language not have any gaps that are critical to the operation of our applications? But remember that security problems do not arise just from the language itself, but also from the programming skills of those who write PHP scripts. Of course, most of the errors can be avoided. But, how can they be avoided? This article is an attempt to answer that question. We will discuss most of the issues with which we meet in life everyday. So let’s start our adventure. For the purposes of this article, we assumed that we do not have access to php.ini, and all operations will be performed from within PHP.

How keep a site secret by using the error_reporting function

A lot of people use error_reporting () to check their website. Obviously this is useful, and this feature should not be abandoned. During development, it is reasonable to use the setting error_reporting () to display all errors. But is that the case with sites that are located on servers already? A page that creates error is actually very easy to break, and it is easy to figure out its structure. One has to know which files on the server may be vulnerable, and we need a script to show which variables. Let’s see how we can log errors, because the error logging function is usually error_reporting (). Here are all the possible settings:

// Turn off all error reporting

// Report simple running errors
error_reporting (E_ERROR | E_WARNING | E_PARSE);

// Reporting E_NOTICE can be good too (to report uninitialized
// Variables or catch variable name misspellings ...)
error_reporting (E_ERROR | E_WARNING | E_PARSE | E_NOTICE);

// Report all errors except E_NOTICE
// This is the default value set in php.ini
error_reporting (E_ALL ^ E_NOTICE);

// Report all PHP errors (see changelog)
error_reporting (E_ALL);

// Report all PHP errors
error_reporting (-1);

The same can, of course, be done by using ini_set (). Here are a couple of examples:

// Turn off all error reporting
ini_set ('error_reporting', 0);

// Report simple running error
ini_set ('error_reporting', E_ERROR | E_WARNING | E_PARSE | E_NOTICE);

Of course, now all the errors will be displayed on the screen of our monitor. But fortunately PHP gives you the ability to hide it from the script by using display_errors. Use this variable from the function ini_set (). Here are two examples that should interest us:

ini_set ('display_errors', 'On');
// Enables the display of errors

ini_set ('display_errors, 'Off');
// disables the display of bugs

Well, you probably already know when to use which value for display_errors. During production, turn it on, and for a site that is already on the server, turn it off.

Why is it so important to use .htaccess?

This file is the main configuration file of a website. It allows you to control access. The first thing we should do is change records links to the so-called nice link URL. This is useful because it helps hide most things that are called by the $ _GET array from the prying eyes of hackers. Unfortunately, it does not help when rules are combined. But it is always seen and passed on to the mechanisms. You can use “.htaccess” to prevent anything from being written in PHP. In addition, using the “.htaccess” can also block users and block all incoming connections on our website from suspicious IP addresses. We can immediately write a script that will do it all for us from a vending machine. This is a much better solution. But of course we can do the same thing in PHP, by putting all of the suspicious IP addresses into a database and denying them access. It’s that simple.

Be sure to turn off global variables

Global variables allow access to the variable from any PHP script. In thousands of existing programming languages, the design includes certain features to quickly develop software. And here they make a fundamental error. If a global variable is enabled, the programmer leaves open a way for an intruder to go through the entire application and find all the places where he has access to a variable. In fact, the exclusion of global variables is actually the first thing to do when the development process begins. Global variables are no longer available in Version 6 of PHP, but they can be used in the obsolete Version 5 and in the commonly-used Version 4. What was register_globals meant to do? It was intended to support the rapid development of applications, but it did not work. This function is used hundreds of times in applications, threatening their safety. But how can we turn off global variables, as we do not have access to the php.ini file? We add the following entry to the “htaccess” file:

php_flag register_globals 0

In addition to global variables, there are many super-global arrays, such as $ _POST and $ _GET, that cannot be excluded using ini_set(). But we’ll talk about them later.

Turn off magic quotes

To save all magic_quotes, the programmer was advised to use addslashes () and other security features in the code, but this doesn’t work as a security measure. There are two fundamental errors in the use of magic_quotes. The first is that if you use this feature and function addslashes (), there are definitely bugs in your code. In addition, when you use magic_quotes, you do not always know when they are really turned on and when they are not. What can we to do to get them completely turned off? Let’s assume that we do not have access to the PHP settings. I use the beloved file “htaccess” and add there the following entries:

php_flag magic_quotes_gpc 0 php_flag magic_quotes_runtime 0

Be sure to never use magic_quotes, and instead use other security functions in PHP.

Anything that introduces the user has to be checked.

This is also true. Anything that introduces the user has to be checked and validated. Use preg_match, as the user inputs the strings. Go ahead and use the function is_null () and is_empty () to be protected against hackers. Use the function is_int (), if you pass through the int variable. If you want to int, it must be int. Test it and see what the function returns. Use all possible limits, and values greater and less than the limit. Use validation using jQuery or function die () to inform the user what to do. Do not be afraid to throw away hundreds of users with interesting messages.

The most common attack, Cross Site Scripting, is in the OWASP Top 10

Note that each web application, not just PHP, allows you to process some data from users. Most also allow for the processing of HTML, both in articles and comments. And here problems often begin. Think about what happens if the user enters JavaScript malicious code that messes with the structure of our application. What will happen then? Now, using JavaScript, you can capture both sessions and cookies. An attacker can easily gain access to user accounts and can do a lot of bad things with these accounts. An account can be removed, passwords can be changed, and logging can be prevented. If we run the portal to commercial services, a hacker can also kill good user accounts and issue them a huge invoice. What is the point here? Of course, we do not prohibit a user from simple editing and beautifying posts. The ability to add emoticons can also be added, but only those emoticons that suit your needs. Use classes to handle BBCode. Allow for simple formatting, but filter all. To handle bbcode, use the function preg_replace (), and many other cool features. Do not be afraid to give users stuff on the site, but try to limit them to stuff and snippets that are controlled by you.

Avoid SQLInjection, also in the OWASP Top 10

The SQLInjection attack is still in the OWASP Top 10 list. Surely it will not disappear from the list in a finite time. Perhaps it never will disappear. Does this mean that PHP programmers are not good enough? No, I do not mean that. I mean that PHP developers do not understand the written word. My advice is that you should not use SQLInjection for application development frameworks; or use it properly, if you must use it. If possible, use your own framework. My is a set of classes that allows you to fully create each web application. But if you write alone, and do not use frameworks, observe the following rules.

Everything you add to the database should be filtered. I mean everything, every variable that queries the database, should always be filtered. Do not be afraid to use the function mysql_real_escape_string (). Please, if you have variables passed as part of the database query, filter them forever. If you pass an int, you do not need to use mysql_real_escape_string (), but then you should always use is_int (). Scan your site for the presence of SQL errors using the OWASP tools. They will show you what you forget when designing your site. Do not let a hacker break it as easily as possible. Raise the bar and raise it fast. Lift it to a level that will prevent a hacker from ever breaking in.

Watch out for session hijacking, also in the OWASP Top 10

The easiest way to capture a session involves the acquisition of the session ID. It can result in very unpleasant consequences for our service. The easiest way is to download the session id and append it to SESSID to the address, which means that the user who makes this attack becomes the “real” user. Acquiring data such as user name and password and posing as someone else is no longer treated as a crime. By using Session_regenerate_id with (true) is a way we can protect against interception of data in the session. The same function without true replaces the current session id with a newly generated one. With the option set to true the session ID is deleted, which will work even if the page is not reloaded. Other methods of preventing session capture are to comparing the IP address, comparing the browser, and a few other things. Maybe someday I’ll show you how to write a fast mechanism to fully secure session. I do not know, we’ll see.

Remote file inclusion, another in the OWASP Top 10

This allows a hacker to send code to a given web page. It is usually used when you want to upload a file via a script. Sometimes we simply forget to validate what we wrote. Using this method, an attacker can to make server-side code or client-side code, can block any service and can manipulate data. PHP can be the reason for the attack if there is no decision on the files sent by $ _POST, $ _GET, $ _COOKIE. This error applies to most of the include () and require (). Here is a PHP script that contains this error:

$file = 'my_file'; 
if (isset ($ _GET['file'])) 
  $ file = $ _GET['file']; 
include ($ file. '. php'); 

Can we change this code to prevent an attack? Why not? To make it a thousand times better, use e.g. switch ():

if (isset ($ _GET ['file'])) {
  $file = $ _GET ['file'];
  switch ($file) {
    case 'noname':
      require_once ("noname.php");
    case "my_file":
      require_once ("my_file.php");
       require_once ("my_file.php");

We must always check our code and take more time to control our code. Never leave anything to chance.


This article should be construed as an introduction to PHP security. Apparently everyone is familiar with these techniques, but at the moment when security has to be considered, it is forgotten. Why does this happen? In the press of work, we forget what we really need to do. Always, always stay in control of all that is caused by the PHP scripts. Do not leave anything to chance and write code in such a way that you do not control it at all. I really try to write good applications and concise code. Good Luck!

Adrian Stolarski is a security researcher for InfoSec Institute. InfoSec Institute is a security certification company that has trained over 15,000 people.