Monday, January 08, 2007

PHP Security Tips

A lot of programmers out there use PHP to do their every day tasks but a lot of them are not very aware of SECURITY issues at all. So this article is intended to those users who actually are not very aware of the security in PHP development. I will provide some basic overview and run through the most common problems and their solution and actually I will tell you some pretty cool tricks so you don't worry about your applications security. So shall we start ?

Short list of security issues:
1. Not escaping user input fields
2. Not escaping SQL queries
3. URL parameters hack
4. Giving direct access to files
5. Configuration of the web server



First of all I shall say that this article will not make you aware of all the problems you might get when fighting with crackers and there are plenty of other hacks that will not be covered here... but this list of SECURITY issues shall be more than enough for your web site to be stable and secure. And second - a completely secure system is virtually impossible.

This is what I call a list of basic security issues which most of the unexperienced web developers are unaware of.

1. Not escaping user input fields
and 2. Not escaping SQL queries

Escaping of a string means the obscuring of the special symbols like HTML or SCRIPT tags which provide native code execution or something of the kind. So escaping means if we put our PHP code in a post on a site which has escaped our post the code wont execute.

Well as you might already think not using this method for protecting your site is a very serious issue. Imagine this web page where you can post a comment. Imagine you can make in your post a whole new page. Well lets just limit our imagination to a JavaScript for redirection. So if a user posts this JS like a comment and all the symbols aren't escaped we will end up with a page which will redirect to somewhere else... so a big minus for our users and probably they will not come back to our site because the HARMFUL user already did his job well to bring our site down. And just in case this seems not so bad for you imagine putting a piece of code which will execute and delete our database or just bring our web server down (without redirecting).

A simple code use that will eventually prevent the closing of an html tag:


//user submited text is: I will brake you code with this " symbol
$str = $_POST['user_submited_text'];

echo addslashes($str);
// Outputs: I will brake you code with this \" symbol


Addslashes function will escape the ' , " , \ and NULL symbols by putting a dash in front of them. Actually addslashes will be more effective for our second issue - SQL queries.
SQL queries are vulnerable to the so called sql injection. It means that you want ot submit a qeury with a value that is submitted by the user but instead of standard WORD he puts a whole string that makes your query end, begins a new query build by himself then ends his query.
And guess what might his query be? Maybe "DROP dbname;" will be appropriate which ofcourse isn't a good query and will drop our database.

So a really useful thing in all the cases is to just use not addslashes but some other function which will escape most of the harmful symbols like < > ? ; " ' and so on.
So a good function to use is htmlspecialchars, mysql_real_escape_string or build a custom one.


3. URL parameters hack
This issue is connected with what the most of the normal web surfers don't really see.
The GET parameters in the URL. Normally these GET params are of great help for the web developers so they can process information across multiple scripts but if those scripts are badly written a potential security hole is open and a cracker might use this against us.
See this example of telling the script to create a page.
http://example.com/pages.php?action=create
Let us say this script gives you control over your pages and you can create, edit and delete your pages. Well normally the delete process would be something like this:
http://example.com/pages.php?action=delete&id=2
Well this will tell the script to delete page with ID = 2. But what if the user doesn't pick one of the links with his assigned pages IDs but puts like ID = 2105. Well he might just got one of our users hate us for deleting his page. So you should be very careful about the usage of URL GET PARAMS in your application. A method to protect is to double check everything especially user rights. I can't give you a code example to protect against this cause it will depend on what you have programmed but you can use isset(), empty() and the $_SESSION super global array to prevent some of the bugs you might INCIDENTALLY leave. Cause you know no body is perfect.


4. Giving direct access to files
Another issue is the use of require_once("script_name.php");.
What is wrong with this? Actually nothing :)
You include a file which will provide certain functionality in another file which you have checked that the user has been logged in and so on... security security security.... but what if the user access this file directly and skip all the checking that were made in the other file?
So providing access to all your script files is a bad idea.
you can always put tons of code in them to make them not execute but!
I said something about tricks right ?
Well most of the web developers use htaccess files to protect files from direct execution or as I said tons of code includes which serves the same purpose. Well here is the tricky part.
While developing your web application make a directory like WEB_ROOT where you will put all the visible parts of the site like all your HTML files, images and so on. The scripts you include one level up in the tree. So you have all the scripts in the ROOT folder and all the things that the users will see in its subfolder named WEB_ROOT. In the WEB_ROOT include just one script file (mostly this is the index.php file) which will control the scripts that aren't directly accessible. And when you deploy your web site just make sure your domain name will load the WEB_ROOT folder.
Why this is tricky?
- you don't need many files for access control
- you don't include unnecessary protection code in your files
- PHP works with the file system (so it can access the files with ../ but HTTP doesn't work the same way and ../ wont bring you the content of the ROOT folder).


5. Configuration of the web server
Many problems come from miss configuration of the web server especially the php.ini file which is responsible for the PHP module of your web server.
While in general this is a custom process you can do the following to protect.
1. Make a config file to include in your project if you don't have/use one
2. with ini_set set some of the php.ini directives so they work as you expect
3. turn error_reporting off when you site is in production state not development
4. and at the end always recommend to turn php into safe mode




I say again that this is far alway from full list of SECURITY issues. But this shall be more than enough if you comply with it to provide your application a stable and secure environment to run.

There is a lot about this topic I will be glad to explain if you leave a comment and ask politely! But I will have to ASK those of you who will find my article unsatisfied to not submit their hate here!

As I used to say: "Love your code, have fun with it and don't hate it" ;)

Cheers!

2 comments:

Simon J Greenhill said...

There are some MAJOR problems with your suggestions.

1) addslashes is stupid. It is NOT for escaping output. Anything that goes to the user's browser MUST be html escaped. This is what htmlspecialchars is for.

2) SQL Injection doesn't work the way you think it does. In most cases appending "; DROP table" to a query will not work, as mysql_query and mysqli_query etc will NOT handle multiple queries (the attacker's going to have to guess the tablename as well).

Do it properly - I wrote something up on this here:
Protecting MySQL from SQL Injection attacks, but there are plenty of other good resources out there describing this in detail.

The "URL Parameters hack" - isn't a hack. This is purely bad coding on your part. The user should NOT be able to perform a 'dangerous' action just by modifying the URL, without proper authorisation. Your application should be checking this at every step of the way.

"require_once("script_name.php");.
What is wrong with this? Actually nothing"

- actually, the PEAR coding guidelines state that require/include etc do not need the brackets, as they're language constructs and not functions.

The good parts - I agree with keeping important files outside of the webroot (but this is not a guarantee either - shared hosting, or file inclusion hacks are a problem here), and yes, turning off all errors on a production site is vital.

--Simon

Явор Иванов said...

I appreciate the comment.
For 1) I stated that HTMLSPACIALCHARS is a good function so a person should have a look at it.

SQL injection is fixed long ago with this problem YES... I just gave the worst case scenario so a person shall see the dark power behind this.

URL param attack depends on how you write the application you say :)
Well everything depends on that :)

About the language constructs yes it is so :) maybe I got a bad habit.

And about the other resources that are there on the web... hell yes :)
there are plenty of good ones but my point is more to point out the easy ones and most harmful so people could avoid them.
I didn't want to gave a full scale overview and I said that :)

Well thank you for you comment!