PHP Security Tips

PHP is a very easy language to learn and many people without a big knowledge in programming are learning it to make their sites more interactive. Unfortunately, there is a big percentage of those who are unaware of the security risks. Here are most common ones:

Never trust any users on your site
Never, Ever, Trust Your Users. Assume every single piece of data your site collects from a user contains malicious code. Always. That includes data you think you have checked with client-side validation, for example using JavaScript. If you can manage that, you’ll be off to a good start. If PHP security is important to you, this single point is the most important to learn.

register_globals
If you’re an advanced PHP programmer, you’ll most probably know about this. register_globals makes every variable that comes into the script global. (ex: my page is index.php and a visitor visits index.php?p=3. my $p variable is 3.)


if ($password == "mypassword") {
$authorized = 1;
}
if ($authorized == 1) {
echo "my important area";
}

If your server or PHP install has register_globals on then anyone accessing your page: page.php?authorized=1 will gain access to it.

There are two ways to fix a problem like this:
1. Create a .htaccess file & put the following: php_flag register_globals off. However; take note that if you have coded your script in an enviroment with register_globals (where $_POST, $_GET, $_REQUEST is not used). It will break your script.

2. Simply insert a $variable = 0 before you utilize your variable which means if anyone tried using ?authorized=1 then it would be automatically unset.

Error Messages
Errors are a very useful tool for both programmer and hacker. A developer needs them in order to fix bugs. A hacker can use them to find out all sorts of information about a site, from the directory structure of the server to database login information. If possible, it is best to turn off all error reporting in a live application. PHP can be told to do this through the .htaccess or php.ini, by setting “error_reporting” to “0”. If you have a development environment, you can set a different error reporting level for that. You can also write error_reporting(0); in the beginning of your script.

SQL Injection
One of PHP’s greatest strengths is the ease with which it can communicate with databases, most notably MySQL. Many people make extensive use of this, and a great many sites, rely on databases to function.

However, as you would expect, with that much power there are potentially huge security problems you can face. Fortunately, there are plenty of solutions. The most common security hazard faced when interacting with a database is that of SQL Injection – when a user uses a security glitch to run SQL queries on your database.

Let’s use a common example. Many login systems feature a line that looks a lot like this when checking the username and password entered into a form by a user against a database of valid username and password combinations, for example to control access to an administration area:

$check = mysql_query(“SELECT Username, Password, UserLevel FROM Users WHERE Username = ‘”.$_POST[‘username’].”‘ and Password = ‘”.$_POST[‘password’].”‘”);

If I enter the following into the “username” input box in the form and submit it:

‘ OR 1=1 #

The query that is going to be executed will now look like this:

SELECT Username, Password FROM Users WHERE Username = ” OR 1=1 #’ and Password = ”

The hash symbol (#) tells MySQL that everything following it is a comment and to ignore it. So it will actually only execute the SQL up to that point. As 1 always equals 1, the SQL will return all of the usernames and passwords from the database. And as the first username and password combination in most user login databases is the admin user, the person who simply entered a few symbols in a username box is now logged in as your website administrator, with the same powers they would have if they actually knew the username and password.

With a little creativity, the above can be exploited further, allowing a user to create their own login account, read credit card numbers or even wipe a database clean.

Fortunately, this type of vulnerability is easy enough to work around. By checking for apostrophes in the items we enter into the database, and removing or neutralizing them, we can prevent anyone from running their own SQL code on our database. The function below would do the trick:
function make_safe($variable) {
$variable = addslashes(trim($variable));
return $variable;
}

Instead of using _POST variables as in the query above, we now run all user data through the make_safe function, resulting in the following code:
$username = make_safe($_POST['username']);
$password = make_safe($_POST['password']);
$check = mysql_query("SELECT Username, Password, UserLevel FROM Users
WHERE Username = '".$username."' and Password = '".$password."'");

If a user entered the malicious data above, the query will look like the following, which is perfectly harmless. The following query will select from a database where the username is equal to “\’ OR 1=1 #”.

SELECT Username, Password, UserLevel FROM Users WHERE Username = ‘\’ OR 1=1 #’ and Password = ”

Unless you happen to have a user with a very unusual username and a blank password, your malicious attacker will not be able to do any damage at all. It is important to check all data passed to your database like this, however secure you think it is. HTTP Headers sent from the user can be faked. Their referral address can be faked. Their browsers User Agent string can be faked.

File Manipulation
Some sites currently running on the web today have URLs that look like this:

index.php?page=contactus.html

The “index.php” file then simply includes the “contactus.html” file, and the site appears to work. However, the user can very easily change the “contactus.html” bit to anything they like. For example, if you are using Apache’s mod_auth to protect files and have saved your password in a file named “.htpasswd” (the conventional name), then if a user were to visit the following address, the script would output your username and password:

index.php?page=.htpasswd

By changing the URL, on some systems, to reference a file on another server, they could even run PHP that they have written on your site. Fortunately, again, this is reasonably easy to protect against. First, make sure you have correctly set “open_basedir” in your php.ini file, and have set “allow_url_fopen” to “off”. That will prevent most of these kinds of attacks by preventing the inclusion of remote files and system files. Next, if you can, check the file requested against a list of valid files. If you limit the files that can be accessed using this script, you will save yourself a lot of aggravation later.

Using Defaults
When MySQL is installed, it uses a default username of “root” and blank password. SQL Server uses “sa” as the default user with a blank password. If someone finds the address of your database server and wants to try to log in, these are the first combinations they will try. If you have not set a different password (and ideally username as well) than the default, then you may well wake up one morning to find your database has been wiped and all your customers’ credit card numbers stolen. The same applies to all software you use – if software comes with default username or password, change them.

Leaving Installation Files Online
Many PHP programs come with installation files. A number of these are self-deleting once run, and many applications will refuse to run until you delete the installation files. Many a times, the install files are still online. If they are still online, they may still be usable, and someone may be able to use them to overwrite your entire site.
_______________________________________________________________
Original article by Dave Child. Released under a Creative Commons License.