Securing basic PHP flaws for newbies [Part 1]

Deadly Ghos7's Avatar author of Securing basic PHP flaws for newbies [Part 1]
This is an article on Securing basic PHP flaws for newbies [Part 1] in PHP.

Introduction



Actually, this has been taken from my blog(www.sampctricks.blogspot.com) and I re-updated the article for Go4expert. I am myself newbie to programming but still I have included here what I myself practice. This is just a basic guide to prevent basic flaws in your PHP based web apps.

PHP is the most used web developing language and with the increased use of it, there have been increase in poorly programmed sites which have resulted in number of admin hacks and sometimes even worse, server rooting. So I am going to give you some ideas for writing secure codes for general coding flaws in PHP. Most of the time, the programmers forget to sanitize the user input in their PHP code & hence, the code becomes vulnerable to some of the common exploits like file inclusion vulnerabilities, SQL injection, XSS & others... The programmer should never trust anything that comes from the clients and so (s)he should try to create whitelist for what is allowed to. So this article is going to give some ideas on preventing these simple vulnerabilities from your PHP code...

Article Description



General steps:
Validate every input.
Secure your file system.
Secure your file upload system.
Secure your file download system.
Secure your database connection codes.
Secure/encrypt the data.

Now lets start with basic programming flaws and securing steps.

FILE INCLUSION : File inclusion vulns like RFI(remote) & LFI(local) are exploited by including another file(other than intended by programmer) & this can be very dangerous as hackers can completely ruin the system. Many programmers write the codes like below:

PHP Code:
<?php

$page 
$_GET['page'];

if (isset(
$page))   #checks if the $page variable page is set or not
{
include(
$page);   #includes the page without checking if it is legitimate or not...
}

?>
Here, the $page variable is taken from URL of the site and there is no checking for the file that is going to be included by PHP script. So hackers can include malicious shells and get access to the server due to this vulnerability.

Also many programmers think that they can patch this vuln with the following snippet(based on real example from one of the Nepali ISPs site)

PHP Code:
<?php

$venpage 
$_GET['page'];
$venpage $venpage ".php";

if (IsSet(
$venpage))
{
include(
$venpage);
}

?>
This scripts takes $page variable from URL, appends .php at the end and includes that file. It seems to prevent the exploit as it is going to include only PHP files from the server but that's not true. Nullbytes (%00) in PHP can be inserted by hackers which terminates the string and removes .php part from the include page.

So let me talk about securing it... There are number of ways to secure it and all are perfect. But, at least for me, the switch is the perfect and simplest method to secure this whole code...

PHP Code:
<?php

$page 
$_GET['page'];

if(isset(
$page)) #check if there's page variable set or not
{
switch(
$page
{

case 
"info":
include(
"info.php");
break;

case 
"about":
include(
"about.php");
break;

default: 
include(
"index.php");
break;

}
}
?>
The above written code is simple yet secured. You may also create the array of valid files and then using in_array() function, you may include the PHP file if its in that array.

Another method is:

PHP Code:
<?php
//ERROR_REPORTING(E_ALL);
if (IsSet($_GET['page']))
{
$page=$_GET['page'];
$page=preg_replace('/[^a-z]+/i','',$page);    //regular expression
include $page.".php";
}
else
{
echo 
"No page set";
}
?>
this also should work fine though as already stated I don't use this one... Its a regular expression method...



SQL INJECTION(SQLi): SQL injections are one of the most prevalent web vulns in the websites and they can be very harmful especially for the commercial sites. But still many sites still remain vulnerable to the SQL injection. & again the problem is the lack of sanitization of GET/POST or COOKIE variables or any other inputs from users... To avoid SQL injection, you need to be as hard as you can. Don't allow any other data types where you assume to be integer types. Don't allow something that is not what you wanted to be accepted by your code. Be as strict as you can for the datatypes.
Now let me show you the simplest form of the vulnerability.

PHP Code:
<?php
//configurations for mysql connection
$host "localhost";
$user "root";
$pass "w000000t";
$db "db_shop";
//connecting to mysql
mysql_connect($host$user$pass);
mysql_select_db($db);

$uid $_GET['uid'];

if (isset(
$uid))
{
$query mysql_query("SELECT * FROM `profile` WHERE `uid` = $uid");
if (
$query)
{
while(
$profile mysql_fetch_array($query))
{
//display or do something here
}
}
}
?>
You can see that this takes uid from GET i.e. from user and works accordingly. It works fine and most of the site visitors won't know about it. But what if someone elite visits the site, (s)he will test the GET variable and change the uid value.
The query runs and runs without any filtering mechanism. A malicious user can hence make damage to the database. So what's the solution for this? Simply, type checking. You won't expect uid to be anything other than integer type. Hence, we will be type casting the $_GET['uid'] as an integer type.

PHP Code:
<?php
//configurations for mysql connection
$host "localhost";
$user "root";
$pass "w000000t";
$db "db_shop";
//connecting to mysql
mysql_connect($host$user$pass);
mysql_select_db($db);

$uid = (Int) $_GET['uid'];    //you say that uid must be integer...

if (isset($uid))
{
$query mysql_query("SELECT * FROM `profile` WHERE `uid` = $uid");
if (
$query)
{
while(
$profile mysql_fetch_array($query))
{
//display or do something here
}
}
}
?>
So this should be secure as the $_GET['uid'] is type casted as integer. Other ways are using the functions is_numeric() which tests if the given variable is integer or not and intval() that would return integer value of variable.
Note that the ways for securing other datatypes is different. I would list you some of the functions so that you can use them to secure your site from SQLi.
Functions to secure SQLi:
mysql_real_escape_string()
addslashes()

The above example was just for SELECT query but you need to watch the other queries like INSERT, UPDATE and DELETE because you can't just trust the user inputs. Moreover, it is always better to strip the inputs to the limited number of characters so that you won't mess up with SQL column truncation vulnerability(google if you want to know about it). Also, always use quotes and brackets in the SQL query strings if your database allows(MySQL does allow).

Cross site scripting(XSS): Its the most prevalent web app vulnerabilities which have been detected even in high profile sites like facebook, microsoft, twitter, etc. It also occurs when you don't sanitize the user inputs. Consider the guestbook which does something like below:

PHP Code:
<?php
if (isset($_POST['sbtGuestbook']))
{
    
$name $_POST['name'];
    
$comment $_POST['comment'];
    
//insert these things into the database
    //now print these infos in the page
    
echo $name."<br />".$comment;
}
?>
Now, in the name or comment field if I put something like <script>alert('samar');</script>
the site is going to display it and as since the HTML tags are not filtered, samar will be alerted in the page. Its just an example. Hackers can redirect users from your site using this exploit by inserting <script>location.replace("http://hackerssite.com.np");</script>
Now let me come to securing it.
PHP Code:
<?php
    $name 
htmlspecialchars($_POST['name']);
    
$comment htmlspecialchars($_POST['comment']);
    
//insert these things into database
    //now print them
    
echo $name."<br />".$comment;
?>
Here I have used the function htmlspecialchars() which converts all html special characters into their equivalent entities. For example, < to &lt; and > to &gt;
Since these conversions are made to tags, they do not work as HTML tags and hence prevent XSS. More functions to use while preventing XSS are htmlentities(), strip_tags(), url_encode(), etc. To make 100% XSS proof site, validate everything like $_SERVER variables too. They too can be compromised to XSS the site.


Some critical functions: Here are some of the functions you should be careful with while using in your script.

passthru(), exec(), system(), shell_exec(), file_get_contents(), fopen(), fwrite(), file(), readfile(), popen(), mysql_query(), etc.

Other Extra tips: Security of your server can be enhanced by doing some hardening through PHP.INI file too and coding in better styles.
1) Turn off the register_globals
2) Set error_reporting to 0
3) Use @ sign before the functions that are likely to fail usually. eg: @include($page);
4) Turn off allow_url_fopen in PHP.INI
5) Turn on magic_quotes_gpc in PHP.INI
6) Always encrypt the sensitive information. For eg. use md5() once or twice to hash your password, or use different hash functions like md5(sha1(base64_encode(md5($str))));


That was the article on securing common PHP exploits for the new starters in PHP programming arena. In the next issue, I might write the ways to secure other vulnerabilities in PHP codes such as RCE, XSRF, Session and cookies. Till then, bye and Be safe.
Regards~
Deadly Ghos7
NOTE: Based on PHP 5.2.5
qforever's Avatar
Light Poster
There's one more advice on file uploading: you always would be sure what exactly you're put in the accesible by HTTP folders. If you would like to allow visitors to upload images - check image size before uploaded file will be copied to destination folder. If you like to upload anything - check that nobody can run uploaded files.
Would be no possibility to upload and run PHP file.
hanleyhansen's Avatar, Join Date: Jan 2008
Pro contributor
This is very good info. A+!!
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
Nominate this Article for Article of the month - Jan 2010
shabbir's Avatar, Join Date: Jul 2004
Go4Expert Founder
If you liked this articles do vote for it for Article of the month - January 2010
PradeepKr's Avatar
Go4Expert Member
If you are allowed and using exec or system command then you should escape the user provided data for any special characters using escapeshellarg()

$cmd = "ls escapeshellarg($user_input)";
system($cmd);

Without escaping user can pass any malicious input and that would get executed on your server.