Jump to content
xisto Community
Sign in to follow this  
vujsa

CMS103 - Securing Your Website Keeping your included files from being accessed directly.

Recommended Posts

I decided to write this article in respose to a possible security hole that was discussed here: http://forums.xisto.com/topic/90154-topic/?findpost=1064347572

 

See Also:

- http://forums.xisto.com/topic/86340-topic/?findpost=1064320566

- http://forums.xisto.com/topic/89461-topic/?findpost=1064342915

 

In the previous 2 articles describing how to create a simple CMS using the PHP include() function, I've discussed how using included files can save a webmaster a lot of time. The downside to using included files is that it is possible for sensitive data to be public accessable. For example, if a hacker was to access and read one of your included files, he may be able to find a security hole in your script. The best way to prevent these kinds of security leaks is to ensure that the contents of any included file can not be viewed direclty.

 

Generally speaking, if your included files have a file extention of .php, then they should be treated like a normal PHP file and plain text will not be displayed if the file is access directly. This is only true if you make sure that you use opening (<?php) and closing (?>) PHP tags in your included files. Otherwise, everything will be treated like plain text when accessed directly. This is how we can have PHP in one part of our file and HTML in another part of the same file.

 

The real issue comes up when a file extention other than .php is used like the .inc or include file extention. Usually, most servers don't automatically parse .inc files as PHP. This can be remedied using your .htaccess file.

 

Editing or creating the .htaccess file in the directory where you have saved all of your included files can tell the server to parse .inc files as PHP.

 

In .htaccess add:

AddType application/x-httpd-php .incAddType application/x-httpd-php .include

Basically, this tells the server to send all files with the extention .inc or .include to the PHP engine.

 

Now that the server thinks these are PHP files, anything inside of the PHP tags will not be sent to the browser without being parsed.

 

Already, we have made a great improvement in the security of our included files but more can and should be done.

 

ALWAYS BE SURE TO LEAVE A BLANK LINE AT THE END OF YOUR .htaccess FILE SO cPanel CAN ACCESS IT IF NEEDED!

========================================================

 

Checking to be sure that an included file is being accessed by it's parent script before sending it's contents will make it very difficult to be viewed directly and/or in raw form.

 

In order to do this quickly and easily, we'll used 2 related PHP functions, define() and defined().

 

The define() function should be used in the parent script, usually index.php.

The defined() function should be used in each of the included files.

 

Assuming that you understood the code in the first 2 articles listed above, here is how the code looks.

Modified code from http://forums.xisto.com/topic/86340-topic/?findpost=1064320566

 

index.php

<?php define( "MY_ACCESS_CODE", true );?><html><head><title>My CMS</title></head><body bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#800080" style="font-family: verdana;"><table width="100%"><tr><td colspan="2" bgcolor=silver><?php include("header.php"); ?> <!-- Used for Banner Advertising etc... --></td></tr><tr><td width="150" bgcolor=red valign="top"><?php include("menu.php"); ?> <!-- Used for The Main Menu... --></td><td bgcolor=navy><?php include("main.php"); ?> <!-- Could be left out and actual content inserted instead. --></td></tr><tr><td colspan="2" bgcolor=purple><?php include("footer.php"); ?> <!-- Banner Ads, Copyright Info., etc... --></td></tr></table></body></html>

header.php

<?php defined( 'MY_ACCESS_CODE' ) or die( 'Direct Access to this location is not allowed.' );?><center>	<a href="http://AstaHost.com; style="border-width: 2px; border-color: teal; font-size: 18pt; font-color: #FF0000;">Advertise Here!</a></center>

menu.php - Here is the real time saver! :(

<?php defined( 'MY_ACCESS_CODE' ) or die( 'Direct Access to this location is not allowed.' );?><span style="font-color: lime;">Search Engines</span><br><a href="http://altavista.com; style="font-size: 8pt;"> ♦  Alta Vista</a><br><a href="http://excite.com; style="font-size: 8pt;"> ♦  Excite</a><br><a href="http://google.com; style="font-size: 8pt;"> ♦  Google</a><br><a href="http://lycos.com; style="font-size: 8pt;"> ♦  Lycos</a><br><a href="http://yahoo.com; style="font-size: 8pt;"> ♦  Yahoo</a><br>

main.php

<?php defined( 'MY_ACCESS_CODE' ) or die( 'Direct Access to this location is not allowed.' );?><p>		 Enter your main content here.  You can simple leave the include statement out of the template and enter the content for the page directly into the index.php.Hope this proves usefull to everyone.

footer.php

<?php defined( 'MY_ACCESS_CODE' ) or die( 'Direct Access to this location is not allowed.' );?><center>	Š 2005 Acme Web Design Inc. - All Right Reserved.<br></center>

Now here is how it works:

define() defines a constant in PHP. This is like a variable in PHP but it will never vary.

define("HAPPINESS", "Hot apple pie.");echo HAPPINESS;
Prints: Hot apple pie.

 

In our case, we only need to define that the constant named 'MY_ACCESS_CODE' is defined so we put true in the definition field of the function like so.

define( "MY_ACCESS_CODE", true );
We don't care if the constant has a value or not just that is has been defined. We define the constant in the file that calls all of the included files. This is the parent script. It is usually the one that is presented to the public like index.php.

 

Next we check to see if the constant named 'MY_ACCESS_CODE' is defined. We do this in our included files. Since the constant is only defined in the file that is supposed to request it, the requesting file is the only one that has direct access to the included file.

When we use the defined() function, we are not actually doing anything as a result of a true answer to the question. The question is of course is "Is 'MY_ACCESS_CODE' defined as a constant?". What we are actually doing is performing an action if the answer to the question is false. If the answer is false, then we kill the script with the die() function. This acts as the custom error message handle for all PHP functions.

 

So we check to see if the constant is defined. If it is then there is no error in the code and the code continues to the next line. If the constant is NOT defined then there is an error and the die() function takes over. The script will do whatever the die() function says and will then terminate. Nothing past the die() function will be used. This includes any HTML that resides below the die() function! So only the

defined( 'MY_ACCESS_CODE' ) or die( 'Direct Access to this location is not allowed.' );
need to be inside of the PHP tags (<?php and ?>).

 

I usually place the defined() function at the very begining of the file since it is the first thing I want to check but theoretically, it can be placed anywhere inside of the file and still work as long as it is not inside of a conditional statement which could cause it to be bypassed.

=====================================================

 

So by ensuring that all of your included files are parsable by the PHP engine and only allowing direct access to included files by parent scripts, you will greatly reduce the risk of security holes in your website. These methods as well as ensuring that your file permissions are set properly will make for a more secure site.

 

Additional security can be added to your website that range outside of this topic but include .htaccess settings which controls how the server will handle any file or file type you define.

 

I hope this information proves to be useful to everyone. :(

 

vujsa

Share this post


Link to post
Share on other sites

Hey vujsa,I have a concern about part of your code that is used in .htaccess.The problem here is you're specifying .inc .include to be used by the PHP interpretter, it may not seem like a problem until you start wondering about what mime-type .inc or .include would originally use. Just because you specified that it should be handled by the PHP interpretter and said application/x-httpd-php what if this did not work?In a situation where .htaccess could possibly fail (1:Million?), be overwritten (does happen), someone forgets to configure it, etc, these files are vulnerable to being viewed as plain/text (possibly?) and you don't want that. At least if you maintained the file extension of PHP, then it's a known mime-type by the server and it should not need to be told how it's handled, though older versions you had to still specify this.I think it's better to call the file something like filename.inc.php rather than just filename.inc as you're not making it compatible across all servers doing this.By allowing this other extension, although I know it was used prior (so was short hand coding and see how that went with compatibility), you now have to be aware of your doings, and that if you had to prevent someone creating a .php file from user input, you need to remember also using .inc .include as well and prevent that too.To sum up what I'm saying, if it's PHP keep to PHP's extension, if it's PERL use PERL's extension, if it's HTML, etc, stick to that extension, same goes for those who like changing the PHP interpretter to handle .html files, it's not the best thing security wise or performance wise for that matter. Keep to what's known.As a semi-related thing, also your code editors will display the right colour coding syntaxing if they knew the filetype correctly.Apart from that your tutorial seems good, though you don't seem to handle situations where include fails. Include will commonly fail if the file does not exist or unreadable, so include('thisfile.php') or code_to(... handle it ...); or better an alternative to display in it's place or if no alternative, then obviously this might need to have been required using require(), where if this fails your script terminates at the point it failed with an allowable error to be displayed.Another security bonus that you missed is that you can store your include files outside of the web root, meaning it's inaccessible from viewing it directly by it's link, which probably destroys the need for the defined() but better safe than sorry.Cheers,MC

Share this post


Link to post
Share on other sites

I think it's better to call the file something like filename.inc.php rather than just filename.inc as you're not making it compatible across all servers doing this.

...

To sum up what I'm saying, if it's PHP keep to PHP's extension, if it's PERL use PERL's extension, if it's HTML, etc, stick to that extension, same goes for those who like changing the PHP interpretter to handle .html files, it's not the best thing security wise or performance wise for that matter. Keep to what's known.

 

Hey thanks for the reply MC. I completely agree with you this time. :( It absolutely drives me nuts to see people use the .inc extention for PHP includes. I don't mind it so much for a sub_extention but PHP should be PHP. I remember from PERL all of the different extentions used on a regular basis and it got had to keep track of everything.

 

The only reason I wrote the article was because I knew so many people use the .inc extention. I figured if they were going to use this method of naming files, they should at least try to add some security. I guess I forgot to add my disclaimer to the tutorial.

Disclaimer:

PHP files should use a .php file extention. If you choose not to follow this very simple rule, then at least add a few security measures to try and protect yourself.:(

 

Apart from that your tutorial seems good, though you don't seem to handle situations where include fails. Include will commonly fail if the file does not exist or unreadable, so include('thisfile.php') or code_to(... handle it ...); or better an alternative to display in it's place or if no alternative, then obviously this might need to have been required using require(), where if this fails your script terminates at the point it failed with an allowable error to be displayed.

 

Another security bonus that you missed is that you can store your include files outside of the web root, meaning it's inaccessible from viewing it directly by it's link, which probably destroys the need for the defined() but better safe than sorry.

 

I tend to not go into error handling in my tutorials. I usually add those functions after I nearly complete my scripts. I guess that I would have an easier time debugging scripts if I'd add the error handlers during the coding proccess.

 

I might look into doing a really detailed error handling tutorial sometime.

 

Another security bonus that you missed is that you can store your include files outside of the web root, meaning it's inaccessible from viewing it directly by it's link, which probably destroys the need for the defined() but better safe than sorry.

 

Actually, I decided not to go into that option because I was afraid it could get confussing for some people. It is easy to forget about a file that is off the grid so to speak. But placing your sensitive files in non-web access directories is a great security measure. Most of use have been doing this exact thing with our .htpasswds files. I guess it is a rather simple concept but I consider it a more advanced security measure.

 

One additional note which MC touched on.

Setting your server to send HTML files through the PHP engine WILL have an effect on your website proformance. Even though the HTML files may not contain any PHP, the engine still has to read the entire file before it will release it to the browser. If your file doesn't have any PHP in it, it should be a HTML file. If your file has PHP in it, then it should be a PHP file.

 

vujsa

Share this post


Link to post
Share on other sites

I have seen it where html files have had php variables like index.html?id=test , was this done using htaccess to parse it as php, or is it some kind of client side scripting like javascript? I cant see why you would need to do this with an html? Can you explain?

Share this post


Link to post
Share on other sites

I have seen it where html files have had php variables like index.html?id=test , was this done using htaccess to parse it as php, or is it some kind of client side scripting like javascript? I cant see why you would need to do this with an html? Can you explain?

They were probably PHP files (or a similar technology, like ASP or JSP) using a .html extension for whatever reason. I know that a certain book on PHP recommends naming your PHP files with .html extensions to mask your use of PHP, thereby making your site just a little tougher for hackers. But I have to agree with vujsa and mastercomputers - it's better to name files as what they are.

If they were static HTML files, they must have had some sort of client-side script using the variable(s). Plain HTML can't do anything with variables - it's a markup language, not a programming or even scripting language. As far as I know (but my knowledge here is small - correct me if I'm wrong), Javascript doesn't have a native function for extracting variables from a URL. You could write a script to do it manually, though, if you really wanted to.

Incidentally, forcing an extension to parse as PHP doesn't necessarily have to be done in .htaccess. If you have access to your server configuration file, you can add the option there, which will change the setting for your whole website, not just the folder you put .htaccess in. Changing the server configuration globally isn't always desirable or feasible (as, for instance, when you are using a free web host!) but it's more efficient than using .htaccess.

Share this post


Link to post
Share on other sites

Hmm =/

Before i edited my .htaccess it looked like this:

# This folder does not require access over HTTP# (the following directive denies access by default)Order allow,deny
Should it look like that =? (be empty)

Now this is how it looks:
# This folder does not require access over HTTP# (the following directive denies access by default)Order allow,denyAddType application/x-httpd-php .incAddType application/x-httpd-php .include

I am using Wamp

By the way: Very Very good tutorial =)
Edited by Feelay (see edit history)

Share this post


Link to post
Share on other sites

Nice tutorial, I'm more of a fixer than a make so there are plenty of ideas here for me.

Feelay try this. Note, as Vujsa said there is a blank line at the end.

# This folder does not require access over HTTP (the following directive denies access by default)#Order allow,denyAddType application/x-httpd-php .incAddType application/x-httpd-php .include

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×
×
  • Create New...

Important Information

Terms of Use | Privacy Policy | Guidelines | We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.