Editor note: This was originally posted on 25yearsofprogramming.com which has since gone offline
PHP is a server side scripting language. You can embed PHP code in your web pages along with HTML. When your server receives a request for a page, it first gives the page to the PHP handler program. The PHP handler outputs HTML code as-is, but when it encounters PHP commands, it executes them. Any HTML generated by the PHP commands is also output. The end result is a web page with content that has been customized on the server before being sent to whoever requested it.
PHP has capabilities that make it a potential security risk:
If you have a website, you can expect to be under constant attack from robots attempting to a) “send in” malicious data and scripts from the outside world, b) trick your server into fetching malicious scripts and running them, c) read and write files on your server. Their goal is to take control of your site and use it for their own purposes.
This article gives configuration settings for PHP and rules for PHP coding that are effective at blocking the most common types of attacks. The configuration lines are few and the rules are simple.
There are two files where PHP configuration commands can go: php.ini or Apache .htaccess.
You should use php.ini as your first choice, if you can. You should be able to use it if:
php.ini specifies the configuration settings PHP will use when it is running on your website. It determines what things PHP scripts are allowed to do and what they are prohibited from doing. The following settings affect security.
In your public_html (the same folder where your site’s main home page is), create a text file called php.ini that contains these lines. Instructions for customizing the text shown in red are farther down this page:
allow_url_fopen = Off
display_errors = Off
display_startup_errors = Off
log_errors = On
error_reporting = E_ALL
error_log = /home/yourUserID/public_html/phperr.txt
expose_php = Off
magic_quotes_gpc = On
magic_quotes_sybase = Off
register_globals = Off
These explanations are brief. This page of the PHP Manual has links to more.
allow_url_fopen = Off is especially important. It prevents URLs (internet addresses) from being used in PHP include() statements and in some other places. A command such as include(“http://website.com/page.php”)will not be allowed to execute. Only files that reside within your website can be included, and you must refer to them by their filepath names, not by their internet URLs. You won’t be able to include a file from a different server, but neither will anybody else. When someone else does it maliciously by embedding the URL in an otherwise innocent-looking HTTP request and hoping that your script can be tricked into including and running their script, it’s called a Remote File Inclusion (RFI) attack. Having allow_url_fopen = Off dooms all such attacks to fail.
Some webmasters think they need to have allow_url_fopen = On because their pages are already coded to use URLs to include files from their own site or from some external site. It is worth expending some effort to try to stopdoing that so that you can turn allow_url_fopen off:
include($_SERVER[‘DOCUMENT_ROOT’] . ‘/page.php’);
$_SERVER[‘DOCUMENT_ROOT’] is a superglobal variable calculated by the server to be the root folder of your site, the equivalent of “/”, which is usually public_html. Note that it does not provide a trailing “/”, so you must provide a leading “/” in ‘/page.php’. Now you have a reliable method to refer to any file without having to use relative paths and without using a URL unnecessarily.
These specify that all errors and warnings will be logged to your error log text file. NO errors or warnings will be displayed on any web page that is sent out from your server. Errors should never be displayed publicly because they can help someone figure out how to attack your server. Remember to check your error log when you are testing new code.
This defines the path and file to which your PHP errors and warnings are logged. Change yourUserID to the cPanel or other UserID assigned to you by your webhost. The filename can be anything you want. The path starting with /home is a common one on Linux servers, but it could vary depending on your webhost. If the above doesn’t work, ask them what it should be. public_html is only shown above as an example of where it fits in the path. You don’thave to put your error log inside public_html. See below.
I recommend using a text file for error logging (as shown above), and not using the “system log” option that you might see mentioned. Your text file will accumulate errors indefinitely until you empty it, while the Apache system log can be flushed unpredictably.
Your error log file should be in an area of your webspace that is not publicly accessible. Any one of these methods will protect it:
With A) and B), you can only view the file with cPanel > File Manager or FTP, not by browser. With C), you can view the file in your browser by entering the password.
Not particularly important, but it doesn’t hurt. The headers that accompany outgoing pages will not reveal that PHP is running or its version.
The PHP manual recommends setting this to Off, and dealing with quotes in a secure manner on your own, but we’re assuming you don’t know how to do that yet, and that you also don’t actually have any need yet for the situations it addresses, so for now the best setting is On.
Another special setting of “magic quotes”. This should be Off.
register_globals = Off is especially important. You’ve probably seen URLs that look like this: http://site.com/index.php?something=somevalue. When register_globals is On, the variable called something is passed into your script with its value set to somevalue. When register_globals is Off, variables passed in like this are not automatically dumped into your script’s variable list. This makes it harder for someone to inject their own code.
This setting is not in the “recommended php.ini” above. I only mention it because you might run across it and wonder what it is and how it should be set. It restricts the permissions with which PHP scripts run. However, some very popular third party scripts, which you might want to use eventually, will not run properly when it is set to On. In addition, if your webhost uses suPHP, safe_mode serves no purpose. Lastly, beginning with PHP 6, safe_mode doesn’t even exist. Therefore, it is best left out of your php.ini file, or, if present, set to Off.
If your webhost does not allow you to create your own php.ini, you can put configuration commands in .htaccess instead. Unfortunately, not all php.ini commands have .htaccess equivalents, but some of them do.
Put the following lines in a part of your public_html/.htaccess file that is not delimited by HTML-style tags such as the <Files></Files> tags in the example in Section 3.1 below. The following lines have the same effects as their php.ini counterparts described in Section 1a) above, but notice that the format of the commands is different:
php_flag display_errors Off
php_flag display_startup_errors Off
php_flag log_errors On
php_flag magic_quotes_sybase Off
php_flag magic_quotes_gpc On
php_flag register_globals Off
php_value error_log /home/yourUserID/public_html/phperr.txt
php_value error_reporting 2147483647
The most important is the register_globals line.
It is very unfortunate that allow_url_fopen = Off has no .htaccess counterpart (although it will in PHP6). Because you cannot stop PHP from reading a file from a remote server, you need to make sure requests that try to do that maliciously are blocked so they cannot reach the PHP processor. A previous article has instructions how to use .htaccess to block requests that might be Remote File Inclusion attacks.
The following two also cannot be set in .htaccess, but they are unimportant:
expose_php = Off
safe_mode = Off
If you ever write code that won’t run properly with the above settings, you are leaving behind your “beginner” status and need to study PHP security more carefully before you go any further. The Security section of the PHP Manual is one reference that should be read at some point, but it isn’t easy and probably isn’t the best place to start.
Your server can give you a complete report of all your PHP settings.
# This denies all web access to your php.ini file.
<Files php.ini>
order allow,deny
deny from all
</Files>
The settings list in Section 1a) was supposed to be as simple as possible, usable by anyone, with a minimum of effort required, but there is one more php.ini setting that’s worth using if you can. Here is an example of its use, with a list of some of the functions that could be disabled for increased security:
disable_functions = exec,shell_exec,passthru,system,eval,show_source,proc_open, popen,parse_ini_file,dl,(comma-separated list of function names)
This tells PHP not to allow the listed functions to be executed by any script in your site. The functions listed above are especially powerful, and many malicious scripts use them. By blocking their use, you block the scripts from causing much of their damage even if they do somehow manage to get into your site and run.
However, some of these functions are used by popular third party PHP scripts such as forums, blogs, galleries, and shopping carts, so the reason I call this an “advanced” setting is that before using this line you must search all the PHP code in your site to make sure you don’t disable functions that your site requires. Nevertheless, disabling functions you don’t use is worthwhile if you don’t mind doing the research.
disable_functions is for php.ini only. It has no .htaccess equivalent.
When the time comes that you need to break one of the Beginner Rules, first do a web search on: PHP security and spend a few days practicing proper coding techniques for the methods and functions you plan to use.
If necessary, email your web host. Ask these questions, and then modify your php.ini or .htaccess file as needed: