Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

[PHP] 5 Helpful Tips for Creating Secure PHP Applications

[R8]ℓσℓ32
Loyal Member
Joined
Oct 6, 2008
Messages
1,396
Reaction score
198
Sometimes a feature-friendly language can help the programmer too much, and security holes can creep in, creating roadblocks in the development path. In this tutorial, we will take a look at 5 tips to help you avoid some common PHP security pitfalls and development glitches.

Tip 1: Use Proper Error Reporting

During the development process, application error reporting is your best friend. Error reports can help you find spelling mistakes in your variables, detect incorrect function usage and much more. However, once the site goes live the same reporting that was an ally during development can turn traitor and tell your users much more about your site than you may want them to know (the software you run, your folder structure, etc). Once your site goes live, you should make sure to hide all error reporting. This can be done by invoking the following simple function at the top of your application file(s).

PHP:
error_reporting(0);

If something does go wrong, you still want and need to know about it. Therefore, you should always make sure to log your errors to a protected file. This can be done with the PHP function .



Tip 2: Disable PHP "Bad Features"

From its earliest days, PHP designers have always included some features to make development easier. Some of these helpful features can have unintended consequences. I call these "bad features" because they have allowed data validation nightmares and created a pathway for bugs to finding their way into scripts. One of the first things you should do when the development process begins is disable certain of these features.
Note: Depending on your host, these may or may not be turned off for you. If you are developing on your own computer or other similar local environment, they probably won’t be turned off. Some of these features have also been removed in the upcoming PHP6, but are ubiquitous in PHP4 applications and are only deprecated in PHP5 applications.

Register Globals (register_globals)


In short, register_globals was meant to help rapid application development. Take for example this URL, , which includes a query string. The register_globals statement allows us to access the value with $var instead of $_GET['var'] automatically. This might sound useful to you, but unfortunately all variables in the code now have this property, and we can now easily get into PHP applications that do not protect against this unintended consequence. The following code snippet is just one common example you will see in PHP scripts:

PHP:
if( !empty( $_POST['username'] ) && $_POST['username'] == 'test' && !empty( $_POST['password'] ) && $_POST['password'] == "example" )
{
	$access = true;
}

If the application is running with register_globals ON, a user could just place access=1 into a query string, and would then have access to whatever the script is running.
Unfortunately, we cannot disable register_globals from the script side (using ini_set, like we normally might), but we can use an .htaccess files to do this. Some hosts also allow you to have a php.ini file on the server.

Disabling with .htaccess

php_flag register_globals 0

Disabling with php.ini
register_globals = Off

Note: If you use a custom php.ini file that is not applicable to the entire server, you must include these declarations in every sub folder that has PHP.

Magic Quotes (magic_quotes_gpc, magic_quotes_runtime, magic_quotes_sybase)



Magic Quotes was a feature meant to save programmers the trouble of using addslashes() and other similar security features in their code. There are at least three problems associated with magic quotes. One problem with this helpful feature is if both magic quotes and addslashes() are used. If this is the case, then you end up with multiple slashes being added, causing errors. The second problem is if you make the assumption magic quotes is turned on and it actually is not. Then all the input goes unchecked. The third problem is that magic quotes only escapes single and double quotes, but if you are using a database engine, there are also many database specific characters that also need to be escaped. It is recommended use that you disable this feature and use proper variable validation instead (see below). Unfortunately, we also cannot disable magic quotes from the script side using ini_set. As with register_globals, we can use .htaccess or php.ini files to do this.

Disabling with .htaccess

php_flag magic_quotes_gpc 0 php_flag magic_quotes_runtime 0

Disabling with php.ini
magic_quotes_gpc = Off

magic_quotes_runtime = Off
magic_quotes_sybase = Off
Note: If you use a custom php.ini file that is not applicable to the entire server, you must include these declarations in every sub folder that has PHP.


Tip 3: Validate Input


In addition to escaping characters, another great to way to protect input is to validate it. With many applications, you actually already know what kind of data you are expecting on input. So the simplest way to protect yourself against attacks is to make sure your users can only enter the appropriate data.

For example, say we are creating an application that lists users birthdays and allows users to add their own. We will be wanting to accept a month as a digit between 1-12, a day between 1-31 and a year in the format of YYYY.

Having this kind of logic in your application is simple and regular expressions (regex) are the perfect way to handle input validation.
Take the following example:

PHP:
if ( ! preg_match( "/^[0-9]{1,2}$/", $_GET['month'] ) )
{
	// handle error
}
if ( ! preg_match( "/^[0-9]{1,2}$/", $_GET['day'] ) )
{
	// handle error
}
if ( ! preg_match( "/^[0-9]{4}$/", $_GET['year'] ) )
{
	// handle error
}

In this example, we simply checked (in the first two if statements) for integers [0-9] with a length of one or two {1,2} and we did the same in the third if statement, but checked for a strict length of 4 characters {4}.
In all instances, if the data doesn’t match the format we want, we return some kind of error. This type of validation leaves very little room for any type of SQL attack.
Regex expressions like those above can be a little difficult to grasp at first, but explaining them is out of the scope of this article. The php manual has some additional resources to help you with validation. The PEAR database also has a few packages such as the Validate package to help with emails, dates, and URLS. Below is an example of the above script in action using 200 as an input for a month, abc for the day and just 09 for the year.

Tip 4: Watch for Cross Site Scripting (XSS) Attacks in User Input

A web application usually accepts input from users and displays it in some way. This can, of course, be in a wide variety of forms including comments, threads or blog posts that are in the form of HTML code. When accepting input, allowing HTML can be a dangerous thing, because that allows for JavaScript to be executed in unintended ways. If even one hole is left open, JavasScript can be executed and cookies could be hijacked. This cookie data could then be used to fake a real account and give an illegal user access to the website’s data.
There are a few ways you can protect yourself from such attacks. One way is to disallow HTML altogether, because then there is no possible way to allow any JavaScript to execute. However, if you do this then formatting is also disallowed, which is not always an option for forum and blog software.
If you want HTML mostly disabled, but still want to allow simple formatting, you can allow just a few selected HTML tags (without attributes) such as <strong> or <em>. Or, alternatively, you can allow a popular set of tags called “BBCode” or “BB Tags,” commonly seen on forums in the format of test. This can be a perfect way to allow some formatting customization while disallowing anything dangerous. You can implement BBCode using pre-existing packages such as or write your own BBCode implementation with regular expressions and a series of statements.

Tip 5: Protecting against SQL Injection


Last, but not least, is one of the most well-known security attacks on the web: SQL injection. SQL injection attacks occur when data goes unchecked, and the application doesn’t escape characters used in SQL strings such as single quotes (‘) or double quotes (“).
If these characters are not filtered out users can exploit the system by making queries always true and thus allowing them to trick login systems.

Code:
 ' OR 1=1

Luckily, PHP does offer a few tools to help protect your database input. When you are connected to an sql server you can use these functions with a simple call, and your variables should be safe to use in queries. Most of the major database systems offered with PHP include these protection functions.
MySQLi allows you to do this in one of two ways. Either with the mysqli_real_escape_string function when connected to a server:

PHP:
$username = mysqli_real_escape_string( $GET['username'] );
mysql_query( "SELECT * FROM tbl_members WHERE username = '".$username."'");

Or with prepared statements.
Prepared statements are a method of separating SQL logic from the data being passed to it. The functions used within the MySQLi library filter our input for us when we bind variables to the prepared statement. This can be used like so (when connected to a server):

PHP:
$id = $_GET['id'];
$statement = $connection->prepare( "SELECT * FROM tbl_members WHERE id = ?" );
$statement->bind_param( "i", $id );
$statement->execute();

One thing to note when using prepared statements is the “i” in bind_param. i stands for for integer but you can use s for string, d for double, and b for blob depending on what data we are passing.
Although this will protect you in most circumstances, you should still keep in mind proper data validation as mentioned previously.

Closing

This short tutorial can only scratch the surface of web security. Ultimately, it is up to developers to ensure that the applications they build are safe by educating themselves about the dangers of the web and the most common kinds of vulnerabilities and attacks. If you wish to read more about security issues in PHP, there is a section on devoted to them.

Credits: Justin Shreve
 
Last edited:
Junior Spellweaver
Joined
Jun 23, 2008
Messages
131
Reaction score
0
Hmm... if I am correct, for your validation example, someone could input say

13-32-2011

And it wouldn't count it as an error because you only check for digits 0-9 and a length of 1 or 2.


Not that good of an example either IMO, since usually with dates, you would use select and option tags in HTML.


However, it did help me understand regex a bit better. :p
 
Ginger by design.
Loyal Member
Joined
Feb 15, 2007
Messages
2,340
Reaction score
653
1. Turn on logging at the application level -- turn it on for errors only globally. For applications you're working on, set it to the highest to get warnings etc. For production applications, unless you have an issue, set it a bit lower so you get some information but you don't fill up logs. But unless it's on a dev system, always, always, always turn the display of errors off. They can break your app if it's AJAX based, they can also display information to an attacker that can help them.

2. These are usually turned off by default in 5.3+.

3. There are regular expressions for checking most form-based input. Some of the big PHP dev kits come with API to check form based input from a template. It's better to move it into a well named function like isDate or isIPAddress, etc. Then you can set up an array (call it a template) for the design of the form with the form element name from $_POST and the type, then make a validation function which will verify all variables that should be there are there (and report an error if criteria aren't met), then loop through each variable, validate that it is proper, then return an array of all of the variables in an associative array. I've done this in some apps and it helps immensely when you have a lot of form submission verification to do.

Also, some built-ins are helpful, for instance checking if an input is a number, and you can (and should) always do a trick like subtracting 0 to convert a variable to a number when you need it as a number.

As s-p-n said, there's more security things to deal with like sessions, XSS (never, ever, EVER print anything to the output stream unless it's clean, NEVER, treat it like a database), databases, file access (I have an example of this I can post from a simple file management cpanel I made for work), etc. Pretty much anything where someone can get information they shouldn't or force your application to do something you didn't mean for it to do is a place where security is important.
 
Mother effin' clouds
Loyal Member
Joined
Apr 13, 2008
Messages
1,534
Reaction score
448
I got a better tip... why don't you just link everyone to the article you taken this from:
 
Junior Spellweaver
Joined
Jul 12, 2008
Messages
130
Reaction score
6
Lol Ian you googled faster than me :p GG.
 
Mother effin' clouds
Loyal Member
Joined
Apr 13, 2008
Messages
1,534
Reaction score
448
Technically that's only 4. 5 is a subset of 1.

Maybe he came up with a 5th?

And technically speaking, both 4 and 5 are also subsets of 3 considering they discuss the importance of 'protecting inputs.' A good validation would successfully filter out 'bad inputs.' We'll just see about it when he posts the final 2. Once again, he should had included a link.

Also, going back to error_reporting, a secure PHP application would make good use of error handling as a whole. Suppressing an error alone in a production environment wouldn't fix the issue, it's always good to log errors where possible and fix them. Besides, sometimes you may identify errors at the production environment that you never identified when you were on your development environment.

@Carter, it's not Google. When one is familiar with the articles he read, one would be aware of it the moment he sees just the slightest abstract of it. I subscribed to 3 of Plus' network RSS feeds.
 
Ginger by design.
Loyal Member
Joined
Feb 15, 2007
Messages
2,340
Reaction score
653
And technically speaking, both 4 and 5 are also subsets of 3 considering they discuss the importance of 'protecting inputs.' A good validation would successfully filter out 'bad inputs.' We'll just see about it when he posts the final 2. Once again, he should had included a link.

Also, going back to error_reporting, a secure PHP application would make good use of error handling as a whole. Suppressing an error alone in a production environment wouldn't fix the issue, it's always good to log errors where possible and fix them. Besides, sometimes you may identify errors at the production environment that you never identified when you were on your development environment.

@Carter, it's not Google. When one is familiar with the articles he read, one would be aware of it the moment he sees just the slightest abstract of it. I subscribed to 3 of Plus' network RSS feeds.

Err that's what I meant.. :eek:

I forgot the numbers, lmao. But yes, the main point is check your damn input, I call that a single tip. So really there's only 3.
 
(oO (||||) (||||) Oo)
Loyal Member
Joined
Aug 6, 2009
Messages
2,132
Reaction score
429
Regarding input validation. In latest php version there is function to validate string using filters. Anyone knows what I am talking about?
 
Back
Top