PHP Security: Basic PHP Security
(Page 1 out of 2)Introduction
Security in PHP has become one of the most popular topics in the PHP community lately, especially with an increased number of exploits and security problems. In this day and age, you must make sure your PHP scripts are airtight, and that they don't have any security problems.
To make sure the security in your PHP scripts are okay, you have to start with the basics: filter input, and escape output. If you haven't got that working properly, your scripts will always be open to security problems. Read this article to learn how to properly do these two things.
Filter all input
When your script reads any input from an outside source, the input must be treated as dangerous and not to be trusted. The most common variables not to be trusted are: $_POST, $_GET, $_REQUEST but also $_SERVER, which seems unlikely but can also contain dangerous data.
Before you do any further processing with data that comes from a dangerous variable, you first have to validate it and possibly filter it. By validating the data you make sure that it contains only what you want it to contain. For example, if you're expecting an e-mail address, your validation function would make sure it's a valid e-mail address, and nothing else.
Let's have a quick example to show you what I mean. In the code below I first get the e-mail address from the $_POST variable, and then proceed to validate the data:
$email = $_POST['email']; # At this point it's still DANGEROUS
// Validate e-mail
if (valid_email($email) == false) {
// Not a valid e-mail address
die('Invalid E-mail Address!');
}
?>
The possibility to inject any dangerous data into our script has already been greatly diminished, by checking the data. The valid_email() function is a standard validation function, which can be found in the PHPit Code Snippet Database.
Even though our data is much safer already, we aren't completely there yet, because we still want to insert the data into a MySQL database, which means we must make sure it's safe to be inserted. PHP has a standard function called mysql_real_escape_string(), which escapes all the important characters. Another good practice is to always put data between apostrophes in the SQL query (if your database allows it, which MySQL does).
To continue our previous example, it now looks like this:
$email = $_POST['email']; # At this point it's still DANGEROUS
// Validate e-mail
if (valid_email($email) == false) {
// Not a valid e-mail address
die('Invalid E-mail Address!');
}
// Make sure e-mail is safe for database
$email = mysql_real_escape_string($email);
// All safe now!
?>
Now the data is completely safe, and can be inserted into the database without any worries. To help avoid mistakes it can be a smart thing to give special and dangerous variables a special prefix, for example:
$d_Email = $_POST['email']; # Dangerous
// Do validation
$s_Email = mysql_real_escape_string($d_Email);
?>
This way you will immediately notice when you're trying to insert a dangerous variable, because it'll show a d_ variable being inserted. I've never used this method myself, but once it you get used to it, it could be a lifesaver!
January 16th, 2006 at 6:57 pm
Good article Dennis. Filter ALL input, escape ALL output. Solid advice!
One remark about prefixing variables to avoid mistakes. That is a good aproach. The method I personally apply is the one Chris Shiflett uses in his book. Start with declaring an empty $clean array. After that add only data to the $clean array after validation. Then, if you want to do something in your script, you only work with the $clean array. See for an example http://phpsecurity.org/code/ch01-3
This makes sure you never process tainted/unsafe data, even if a variable hasn’t been declared earlier on in your script. For example, if I process some data like this:
$clean = array();
$email = $_POST[’email’];
$sql = mysql_real_escape_string($clean[’Emali’]);
as you can see, there’s a typo in the last line. But apart from the fact that my script probably doesn’t work as intended, it is not dangerous. The variable “Emali” can not be injected from outside, because I declare the $clean array empty at the start of the script.
I find this approach very useful.
On the other hand, if I would have processed the line as:
$Email = $_POST[’email’];
$sql = mysql_real_escape_string($Emali);
the variable $Emali would not have been declared and could be injected from outside.
Hope I explained it well. There’s a lot to consider when you want to write secure scripts, so it’s good you give it some attention Dennis! And the links you provide are indeed excellent reading material for further study.
January 17th, 2006 at 3:20 pm
$var[’email’]='’;
$var=array_merge($var,$_GET,$_POST);
$sql_query=”select * from table where email=’.addslashes($var[’email’]).’”;
if in php.ini -> magic_quote_gpc=on
$sql_query=”select * from table where email=’.addslashes(stripslashes($var[’email’])).’”;
January 17th, 2006 at 4:11 pm
Hi, Sorry to be really picky, but i wouldn’t call this validation.
[code]
// Do validation
$s_Email = mysql_real_escape_string($d_Email);
[/code]
Thats more what i would say is escaping, validation is checking the length and the characters contained within the username/email address. Stripping out HTML tags etc…I suppose you could call it data cleansing.
Sorry to be a picky swine :)
January 20th, 2006 at 1:23 am
> Start with declaring an empty $clean array. After that add only data to the $clean array after validation.
Or better yes, use perl -T, and have the language *enforce* separation between validated and unvalidated data.
January 22nd, 2006 at 10:02 pm
Matthijs: I really like the idea of the clean array, and it does prevent the mistake you describe, which is probably an all too common mistake, especially because a typo is easy to make.
James: I kinda agree with you, although the valid_email() example I have is a good example of real validation.
January 23rd, 2006 at 9:53 pm
[…] First one is PHP Security: Basic PHP Security. It treats the basics of securing your PHP applications (Filtering the input and escaping the output). […]
May 1st, 2006 at 9:48 pm
valid_email() is not available at http://phpit.net/code/
It would have been nice to see.
May 2nd, 2006 at 11:42 am
Hi Brian,
You’re right, and I’ve posted it now, at:
http://phpit.net/code/valid-email/
I’ve also updated the article. Thanks for letting me know.
May 8th, 2006 at 5:18 am
[…] http://phpit.net/article/php-security-basic/1/ […]
May 24th, 2006 at 12:34 pm
Italian resource / risorsa italiana sull’argomento: programmazione sicura in PHP:
http://www.scuolaelettrica.it/buratto/php2/PHPSec.htm