15+ tips to secure your php application

Php is used to write web applications which are online and publicly accessible. Therefore security is a fundamental necessity of these applications to keep the data safe and free from unauthorized access.

Below are a bunch of simple tips/hacks/ideas to design your php applications to have better security.

The Code

1. Avoid short tags

If they are disabled on some server , then all of a sudden the whole php code will be displayed even before you are informed about it.

<?
$a = 5;
?>

This will run fine when short codes are enabled, but when not, the whole code will be dumped to the browser.
As of php 5.4 the short echo tags (=) are always enabled, not the short open tags.
Also enable short tags on your server.

2. Validate all user input

All input coming from the user , in the form of POST and GET must be validated to be acceptable by the application logic.

3. Escape query data

Escape all data that goes inside a query and for the better avoid direct sql queries in your application.
Use somekind of abstraction like activerecord etc.

One small sql injection vulnerability is enough to allow a hacker to completely take over the system. Tools like sqlmap take only a few minutes to this. So if there is even a single page with a sql injection vulnerability in the whole site for example

http://www.site.com/path/page.php?id=5

where the id is being used in an sql query and is not escaped, this is a door big enough to allow a hacker to do anything on your system. So be very aware of sql queries and ensure everything is secure.

The above piece of code looks quite OK except that the user input in $term is being echoed directly back.
Consider the url

search.php?term=<script>alert('hi');</script>

The script tag will be echoed in the body and the code in it would be executed. Ofcourse its a clientside problem and the code is executed in the user's browser, but still this kind of vulnerability has all the potential a hacker would look for.

Recent versions of Google Chrome would block it saying "Refused to execute a JavaScript script. Source code of script found within request." Firefox still executes it.

XSS is mostly used to inject javascript code to steal cookies of legitimate users who are logged in. The hacker can first inject a complete script like this

Now whatever will be echoed from $term would not have any html code.
Other functions like strip_tags and htmlspecialchars can also be used to clean the input data.

session.cookie_httponly

This php.ini setting specifies the 'HttpOnly' flag in the Set-Cookie field of the http headears. By specifying the HttpOnly flag, we instruct the browser to not expose the cookie to client side scripting language like javascript and use it only for the http communication.

session.cookie_httponly = 1

As of now, all modern browsers support this option and hence it is a quick way to protect the cookies. It would make harder for an attacker to steal the cookie and hijack the session.

5. Always name your file as only .php

Although this is a not very significant to mention point, but still there have been instances of this particular security flaw.

Ensure that all php code files have the extension ".php"
Lets say the database credentials are stored in a separate configuration file and that the file has been named as 'config.inc'.

Now if this file is opened in the browser, the contents will be displayed right away.
Hence never name your files to anything else except .php

6. Salt the passwords and use stronger encryption like bcrypt

Md5 is a very popular encryption algorithm/function being used by php developers. The md5 function gives the hash rightaway.

$hash = md5($password);

However md5 is not a fully secure way to store passwords. Most users tend to keep a 5-8 character password, and whatever be the complexity of such a password, it can be easily cracked by just bruteforcing on a normal computer/pc.

Moreover even bruteforcing might not be necessary, just typing the hash on google.com would reveal the password on some password cracking/rainbow table website. Although users are repeatedly told to keep a strong password its not enough.

To overcome this problem developers often use "salt". The add some more text to the password before hashing it and then do the same when comparing user provided password.

$salt = 'SUPER_SALTY';
$hash = md5($password . $salt);

Adding a salt increases the length of the password, and hence its complexity. So the time required for a brute force program to crack it increase by a huge span.

Along with salt, its a good practice to use a longer(slower) hash algorithm like sha1, sha2 etc. The slower the hashing algorithm, more the time required by a brute force program and hence better the strength.

Bcrypt encryption is even more complex than the sha algorithm and considered more secure. Check the php crypt function.

7. Protect against CSRF

CSRF stands for Cross Site Request Forgery. In this attack a hacker makes a legitimate user do an action on the target web application, without the user being aware at all that he is doing something on the target website.

Lets say a certain url in the application performs some database changes

update_info.php?id=123
delete_record.php?id=123

The problem with the above url is that, what if a hacker makes a legitimate user call such a url without the user actually noticing it.

And now ask the user to open this webpage. Now since the user is logged into the application the url will be triggered and whatever action necessary would be taken by the script.

So basically a hacker has made the request through the user. This is "request forgery".

So technically speaking the problem here is that the server is not able to identify if the user willingly called the url or not. Hence there needs to be a mechanism for this.

A simple way to verify this is by asking the user for double confirmation when doing important tasks.

A more robust and generic solution is to enable the server to identify each request with a key/random value. Forms can contain a hidden input field with a random value that was generated and saved in the session to identify this form submission.

Now if a hacker tries to forge a request he would run out of the csrf key/token and his attempt to perform the request on behalf of the actual user would fail. Only if the user actually loads a url/page with his own wish, would it contain the csrf protection key and then if the user makes the request, would the task be really executed.

Securing the Session

8. Regenerate Session ID

It is a good idea to regenerate the session id at specific events or intervals. It might help if the earlier session id was hacked.

9. Lock the user agent during a session

This can help prevent session hijacking. It is simply about checking if the user agent of a user changed or not. If it did , then logout the user and ask to login again. First save the user agent signature when the user logs in. Then on every request compare the current user agent with the old user agent.

10. Store sessions in database

By default sessions are stored in files. Many applications are hosted on shared hosting environments where the session files are saved to /tmp directory. Now this directory may be readable to other users. If unencrypted the session information will be plain text in the file :

userName|s:5:"ngood";accountNumber|s:9:"123456789";

There are many workarounds for this. Encrypt the session information with suhosin. Check out the Features.

Store sessions in database. Sessions stored inside database are not visible like files. They are only available to the application using it.

11. Force single session

If needed , make sure that a user is not logged in from 2 locations at a time. If another login takes place , then logout the previous login. This is useful on websites that exchange confidential data , for example an online shopping website.

This is easy to implemented when sessions are saved in database. Simply delete any previous login record of a username on every login.

The Setup

12. Configure the database user with care

Make sure the database user does not have privileges to execute command or write to local filesystem. If there is an sql injection vulnerability somewhere in the website and the database user has write privileges, then this is sufficient for a hacker to take over the server completely just by using simple tool like sqlmap.

So the permissions of the database user should be set according to needs. It is a good idea to have a separate user for use by the web application that has only the minimal required privileges on the database system. Or have separate database users for viewing and modifying the database.

13. Disable directory content listing

Using htaccess

Putting the following the .htaccess file shall disable directory listing.

Options -Indexes

Using index.html

If the server does not allow this, then the easiest way is to put a dummy index.html file in all directories.
So that when directory path is accessed, the index.html will open up.

14. Keep resources outside WEB_ROOT

When hosting applications on a server , the path is generally like this :

/var/www/
OR
/home/username/www/

All web content is kept inside www , then only it is accessible on a website. But those contents which are not meant to be directly accessible from a url , can be kept outside the /www.

By doing this the files automatically become invisible to outside world even if directory listing is enabled.

Upload files to a location outside webroot

Applications that allow users to upload files can put the uploaded files in a location that is outside the web root. This can help in a situation of arbitrary file upload. If a hacker were to find such a vulnerability he would try to upload a shell script and execute it by triggering from the browser. Now if the file is outside the web root, then even if the hacker would know the path to the file, it would be harder for him to execute the shell.

15. Disable display_errors in your php.ini file

Do not wait to turn off display_errors in your php script using ini_set or htaccess or anything similar.
Compilation errors that occur before execution of the script starts will not obey any script rules and would be displayed right away. Hence display of errors should be disabled right in the php.ini file in production environment.

16. Setup correct directory permissions in the production environment

Directories should have proper permissions with regard to the need of being writable or not. Keep a separate directory for temp files, cache files and other resource files and mark them writable as needed. Everything else like the directory containing core application code, library files etc should be unwritable.

Also directories (like temp) which can contain resource files, or files with other information should be guarded well and be totally inaccessible to the outside web. Use htaccess to block all access to such directories

This site, binarytides.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to Amazon.com.