Securing PHP Include Files

Posted November 23rd, 2006 by Mike Cherim

One of the great things about the PHP server-side scripting language is the ability to “include” files. Using includes you can share files across several pages. For example, if you’re not using a functions library to handle global page sections, you can create a file called header.php, put some variable hooks in it to handle a dynamic title, keyword set, and description, then use this one file for all your web pages. This can save a tremendous amount of initial work when creating a site, plus it can greatly reduce maintenance down the road if you want to make changes. But the web being what it is, it is possible to access some includes directly and thus you may want to secure them.

Of course this may not be a big deal, but with some files it can be. Moreover, I suppose a little bandwidth can be saved by limiting bogus HTTP requests. Thus, you may want to keep certain files from being accessed out of context, and here I offer three simple things you can do to help prevent this.

Robots Roadblock

You can prevent honest ‘bots from accessing directories by simply adding your global includes directory(ies) to your robots.txt file. To do this create a file called robots.txt, target all user agents with the asterisk, then write a Disallow order for your include files’ directory(ies). Place this file on your domain’s root or index level. Example:


User-agent: *
Disallow: /includes/
# You can and should secure other folders too, like...
Disallow: /images/
Disallow: /admin/

Null Indexing

The next thing you can do is to create a null index in your includes directory — or any directory that doesn’t have an index of its own — keeping people and ‘bots from accessing the directory structure and thus seeing the included files’ names. To do this create an index.php file and put a one-liner in it, like so:


<?php // See no evil, speak no evil, hear no evil, do no evil ?>

Want to be witty? Send a message (the text in the example above won’t be seen) — but you might want to post a link back home or to a site map if you do it this way:


<?php exit('<h2>What are you looking for? Do you need a <a href="/sitemap.php">map</a>?</h2>'); ?>

Optionally you can create a redirect index and simply send snoopers away. In this a example, the wandering visitor is sent to a typical site map page. The disadvantage to this method, and this is improbable with legitimate visitors, is that it may confuse them being redirected:


<?php header("Location: /sitemap.php"); exit; ?>

Lock ‘em Up

The third measure is to “lock” your PHP includes by creating a ping-pong variable match and writing a conditional statement to look for it and present the include’s content. Please note that in the example code blocks below I include a file. If the file was a header, you’d probably want to require it so the page itself couldn’t be accessed without that ever-important file (or any file that you require. To do this substitute include or include_once for the instruction require or require_once.

Part One - The Lock: Below I wrote a simple error statement while exiting the script. The condition here is that if $ping doesn’t equal pong, then the error is returned. If it does pass the condition the rest of the page can be accessed by the requesting page. This is placed at the top of the file that is included.


<?php
if ($ping != "pong") {
     exit('<h2>You cannot access this file directly!</h2>');
}
?>
  Your file content or the script to be executed goes here.

Part Two - The Key: This goes in the file or page doing the including or requesting. It is here that $ping does equal pong and just below that the file is included. The include is allowed to get the file’s content because the condition is met. Place this where ever you want the included content or structure to be.


<?php
   $ping = "pong";
    include_once("include_file.php");
?>

Simply Exemplary

I created an Example Page that is calling for or requesting an include — some Lorem ipsum placeholder text actually. I also offer a link to the actual locked Include File so you can see the lock in action. Please note that my error message example is a lot more extensive than it really needs to be, but I wanted it to be a valid page since it is for example purposes.


17 Responses to: “Securing PHP Include Files”

  1. Dan responds:
    Posted: November 23rd, 2006 at 7:33 am

    A fourth option, and the one I prefer, is to keep include files outside of the web root. Your PHP scripts can still access and include them using either relative or absolute paths, but no-one’s going to have direct access from the web.

  2. David Zemens responds:
    Posted: November 23rd, 2006 at 8:38 am

    I am really green in this area of file security, but as Mike knows I am learning fast about hackers et.al., so I find this post quite interesting.

    Dan - I am interested in learning more about your concept, can you refer me to more information about it?

    Mike - Another great post and an additional classroom lesson in securing my websites!

  3. Robert Wellock responds:
    Posted: November 23rd, 2006 at 10:51 am

    By putting it outside the root you place your entire website in a folder (rather than root) on your host and get your domain name pointed to that folder.

    Usually I’d change the extension and use .htaccess “Deny from all” myself.

  4. Dan responds:
    Posted: November 23rd, 2006 at 12:25 pm

    @David: Say your web root is /path/to/webroot/, and you have a site served from /path/to/webroot/mysite/, you just create a folder below the web root for your includes, such as /path/to/includes/

    In your PHP files, e.g. /path/to/webroot/mysite/index.php, you can include files from that folder using:

    include "/path/to/includes/myinclude.inc.php";

    or

    include "../../includes/myinclude.inc.php";

    Personally I’d recommend the former method - using relative paths can quickly get messy in more complex sites. I would also declare a global variable containing the include path (or paths), which makes moving to another server or another location on your server painless.

    @Mike: Hopefully that will make it clear. No-one can access myinclude.inc.php directly, since it resides outside the web root (i.e. http://mysite.com/index.php will include the file, but http://mysite.com/includes/myinclude.inc.php doesn’t exist).

  5. Robert Wellock responds:
    Posted: November 24th, 2006 at 6:03 am

    Usually *.inc but it is not the most sensible if you want the extra security.

  6. Adam responds:
    Posted: November 24th, 2006 at 11:17 am

    Generally I use a variety of methods. Everything that is listed above (I just happen to prefer defining constants as opposed to variables.)

    For sensitive information, such as initial variabel requirements (MySQL password, etc) I place those above my web root. But, for source documents, I generally do not keep them above.

  7. AD responds:
    Posted: November 28th, 2006 at 11:40 am

    Isn’t it easier just to put your includes in a “includes” folder and put a .htaccess file in it, denying access? Robots.txt can also help, but it only stops those robots that read and follow the instructions, others activelly look for robots.txt file and follow it, assuming it must be a weak point in your system?

  8. Lee Underwood responds:
    Posted: November 28th, 2006 at 1:00 pm

    There is another, easier way to access an include directory outside of the root directory. In the php.ini file is a section called “Paths and Directories”. In there is a parameter called “include_path”. This sets all of the directories where the PHP interpreter looks for include files. For instance, if your Web site root is:

    /home/yoursite/htdocs

    then create a directory “/home/yoursite/includes” and place it on the line, i.e. :

    include_path = “.:/home/yoursite/includes:/usr/local/lib/php

  9. neuroxik responds:
    Posted: December 6th, 2006 at 7:24 pm

    Very enlighting methods, pretty much all useful! I personally used Mike’s method intuitively, using variables declared IN the including file and argued against its value in the include’s head. The NULL method is pretty useful for folders that contain big files too, like wallpapers or MP3’s. Thanks everyone for all these methods.

  10. NY responds:
    Posted: December 15th, 2006 at 5:41 am

    I’m renting space on a shared server. I only have access to /serverroot/path/to/my/files/htdocs/. In that folder I have my log files, a folder for each one of my sites, and a folder where I want to store passwords for apache. Does anyone know how I can access the passwords folder in /serverroot/path/to/my/files/htdocs/site1/.htaccess

  11. NY responds:
    Posted: December 15th, 2006 at 5:43 am

    Sorry, in case it wasn’t clear, I meant from “Does anyone know how I can access the passwords folder from the file /serverroot/path/to/my/files/htdocs/site1/.htaccess”

Sorry. Comments are closed.




Note: This is the end of the usable page. The image(s) below are preloaded for performance only.