Tutorials

PHP Security

by Daniel Egeberg on Jun 30, 2008 12:40:06 PM

2. Error reporting

Error reporting is a good thing, right? It gives you valuable insight into why your application failed. It gives you useful information such as what happened and where it happened. This information is essential in order to fix the bug. However, you might not be the only one who is interested in knowing why your application failed. By giving the user the details from the errors and/or exceptions thrown by PHP you are giving valuable insight into how your application works. Apart from the source itself, this is one of the most valuable intelligence the attacker might gather when looking for vulnerabilities in your application. Therefore, you should never output the error to the screen when your application is running in a production environment (the live setting in which your application runs when it is available for public use). In your development environment (e.g. on your local computer) it is perfectly fine to output the errors because there are nobody but you to see them and it is easier than having to check an error log when something fails unexpectedly.

So what should you do when you have launched your new killer app? Bugs might still appear and you need the before-mentioned information in order to fix them. What you can do, and should do, is write the errors into a log file. Actually, PHP does insert all errors into a log file on the server by default. However, if you are on shared hosting then you will most likely not have access to that file and it will therefore be necessary to write it into your own file. There are a couple of php.ini directives that are relevant to our problem:

  • display_errors this directive controls whether PHP errors should be sent to the screen. In a production environment this should always be turned off.
  • error_reporting this directive controls which errors that should be reported. You should set this to E_ALL and you should fix all issues that appear by doing this.
  • log_errors this controls whether errors should be logged to a file. I would recommend that you always turn this on.
  • error_log this is the path of the file errors should be written to. This is only applies if log_errors is turned on obviously.

Here is how I would recommend that you configure the before-mentioned four directives:

Table 2.1: Recommended Configuration
Directive name: Production: Development:
display_errors Off On
error_reporting E_ALL E_ALL
log_errors On On
error_log varies varies

How error_log should be configured obviously depends on how your directory structure is setup (more on that later in this tutorial).

2.1. Setting the directives

There are a number of different ways you can set the directives in order to achieve the most secure and efficient error handling as I talked about before. If you already know how to do that then you can skip this section.

First and foremost there is changing the values directly in php.ini. However, this is only possible if you are the administrator of the server so for many people this is not an option.

Apache has some configuration files called .htaccess where you can configure Apache directives for the particular folder (and sub-folders) the file is located in. Some hosts do not allow you to use this, but if you can then the PHP module has a directive called php_flag which allows you to set PHP directives. You simply do it like this:

php_flag directive_name directive_value

Note that you cannot use constants like E_ALL so you will have to use their numeric values. E_ALL's value is currently 8191, but that might change in the future so you should check the new value if you update a major version. You can see the constants regarding error reporting at any time here.

So for our production environment you can do this:

php_flag display_errors off
php_flag error_reporting 8191
php_flag log_errors on
php_flag error_log /home/someone/logs/php_errors.log

A third option is to use to use PHP's ini_set() function. That function takes two arguments: the name of the directive to set and its new value. You can use the constants here. There is a function called error_reporting() which you can use to set the error reporting instead.

Comments

You wrote a very nice tutorial here. I'm going to keep all these security advices in mind.

1. John McKenzie on Jun 30, 2008 4:07:27 PM

a great article,
definitely bookmarked.

2. HoTDaWg on Jul 1, 2008 9:46:22 PM

I actually created a post in the Forums asking where to find a good tutorial on PHP security: it was right here on the home page!

3. rupertrealbear on Jul 2, 2008 6:40:55 PM

Great tutorial - explains alot of technical stuff definately recommended

4. Wasim Ilyas on Jul 11, 2008 8:36:42 AM

about the mysql injection, how would such a user find out the name of the table/structure of the table so they could put something to damage the database?

is there a way of stopping them finding out the database/table structure?

5. Flames on Jul 24, 2008 8:36:44 AM

Flames: It could be guesswork, but there are also queries that will allow you to see how the tables are laid out. It could also be an open source app, and it that case it would be as simple as checking the source.

6. Daniel Egeberg on Jul 24, 2008 10:00:29 AM

k, i've been trying to stop mysql injection and although its taken time i finally got it to work without random apostrophes being put in places :D.

7. Flames on Jul 24, 2008 11:07:42 AM

Views: 17435 lol

8. dezkit on Jul 26, 2008 9:14:19 PM

One part is missing, security problems related to emails.

9. Hervé Thouzard on Jul 27, 2008 3:11:32 AM

good stuff!

10. libertyct on Jul 28, 2008 10:44:46 AM

Im happy I found this tutorial - dont understand lots of stuff but will re-read so that it sits.

11. Dorothy Wegmueller on Aug 5, 2008 6:14:18 PM

Well, feel free to ask in the forums if there is anything specific in the tutorial you need help with :)

12. Daniel Egeberg on Aug 5, 2008 7:53:32 PM

Very nice tutorial indeed. It is very helpful for newbie's like me.

13. cyberbuff on Aug 11, 2008 4:57:40 AM

Excellent tutorial. I've had experience with other scripting languages and decided to try PHP. This is really a great start what to look out for and how to design with these dangers in mind.

One question about the include(), mostly for db access. Some showed using a config.pm that would contain passwords to the db.

Would you consider this secure?

mkdir public_html/secure
chmod 711 public_html/secure
create the config.pm containing the db access

in the php script, I add
include('../secure/config.pm');

Would it be better to not be in the document root at all?
I notice in the tree, the config dir is in the system root, not doc root.

Thanks

14. budman85 on Aug 12, 2008 8:11:32 PM

The safest way would be to not place it within document root at all.

15. Daniel Egeberg on Aug 13, 2008 11:10:32 AM

Daniel, great article, was a good read and learned a lot (implementing some of this stuff as I'm writing this.) In doing so, I've noticed that the error_reporting and error_log statements in .htaccess files seem to not work unless they are preceeded by php_value, and not php_flag as stated in the article. Feel free to correct me if I'm wrong, I just thought I'd point it out in case anyone else ran into the issue.

Thanks again :)

16. vnums on Aug 15, 2008 11:15:05 AM

the pdf article for download just gets a 404

17. Brad Floyd on Sep 17, 2008 11:13:51 PM

Ooops... sorry about that. It's back up now.

18. Daniel Egeberg on Sep 18, 2008 1:25:08 PM

cool :-) Just thought I'd point it out since security is one aspect people need to pay more attention to I agree

19. Brad Floyd on Sep 18, 2008 7:34:22 PM

However, wouldn't RFI only be an issue if PHP - Register globals is turned on?

Note some shared hosts has it disabled by default.

20. BlueBoden on Nov 11, 2008 4:20:41 AM
Login or register to post a comment.