PHP link control system - php

I have a question about "link control system" in PHP. The idea is to make script that could make different links than original - something like friendly links with .htaccess. In .htaccess make rule to redirect all traffic to script file - for example linkprocessor.php then in this file should be some conditions, mysql connect and pattern grabber from database(friendlyurl and originalurl columns). So if we write full address - example.com/defined-address it will redirect us(but not change address) to linkprocessor.php and then script is checking if /defined-address is in database, if is it will include certain(based on friendlyurl) originalurl file. Is that script would be optimal? That script could prevent from "hackers".
Example:
example.com/defined-address -> linkprocessor.php -> SELECT originalurl from table WHERE friendlyurl = /defined-address -> include originalurl
=> can be written incoherently but its hard to explain that precisely

What you are asking about here is the Front Controller pattern http://en.wikipedia.org/wiki/Front_controller.
There are various ways to implement it, using a sql database to map URI strings to files to include is a valid way to do it, but might be overkill. The same information could probably be hard coded in a php array.
The standard way to prevent hackers is to only allow whitelisted files to be included. In your case you are using an explicit map to determine which page to include, so it is not an issue.
Some code to get you started:
<?php
$map = array('/home' => 'included_1', '/details' => 'included_2' ... )
if (array_key_exists($_SERVER['REQUEST_URI'], $map)) {
include $map[$_SERVER['REQUEST_URI']]
}
else {
// Send a 404 response
}

What you're looking for is the Front End Controller design pattern.
You described the basic method for solving this, which is to redirect all incoming requests (minus requests for static content such as images, CSS files and JS files) to a single file. Generally this file is the index.php file in the site's root directory, but can be any file.
You can accomplish this redirection using .htaccess on Apache servers or web.config on IIS servers. For .htaccess you can google mod_rewrite and get a load of information that will help you along.
Once you have all of the requests being directed to your Front End Controller, you need to determine what the request is asking for. You can inspect PHP's $_SERVER['REQUEST_URI'] to see what the request is, and handle it accordingly.
The most extensible solutions to this problem that I've seen rely on controllers (classes) being in a specific location and 'static' files being in a separate location. Doing something like the following would make it trivially easy to extend the requests that your site will respond to:
/**
I am assuming at this point that the variable $request is an array
representing the current request. For example, if the request is for:
http://www.example.com/dir/page, $request will contain two entries,
'dir' and 'page'
**/
if(file_exists('/controllers/' . $request[0] . '.php')) {
require_once '/controllers/' . $request[0] . '.php';
$controller = new $request[0]();
$controller->dispatch($request);
} else if(file_exists( '/static/'.$request[0] . '.php')) {
require_once '/static/' . $request[0] . '.php';
} else
throw new Exception('404', 404);
The above is more pseudo-code than actual code, I won't guarantee that it will actually run but the idea is there.
To add another controller to your system, you would simply write a class, make sure that it has a dispatch method, and put it in the proper location.

Related

How to keep a php file from being executed by typing the exact page url [duplicate]

I have a php file which I will be using as exclusively as an include. Therefore I would like to throw an error instead of executing it when it's accessed directly by typing in the URL instead of being included.
Basically I need to do a check as follows in the php file:
if ( $REQUEST_URL == $URL_OF_CURRENT_PAGE ) die ("Direct access not premitted");
Is there an easy way to do this?
Add this to the page that you want to only be included
<?php
if(!defined('MyConst')) {
die('Direct access not permitted');
}
?>
then on the pages that include it add
<?php
define('MyConst', TRUE);
?>
The easiest way for the generic "PHP app running on an Apache server that you may or may not fully control" situation is to put your includes in a directory and deny access to that directory in your .htaccess file. To save people the trouble of Googling, if you're using Apache, put this in a file called ".htaccess" in the directory you don't want to be accessible:
Deny from all
If you actually have full control of the server (more common these days even for little apps than when I first wrote this answer), the best approach is to stick the files you want to protect outside of the directory that your web server is serving from. So if your app is in /srv/YourApp/, set the server to serve files from /srv/YourApp/app/ and put the includes in /srv/YourApp/includes, so there literally isn't any URL that can access them.
I have a file that I need to act differently when it's included vs when it's accessed directly (mainly a print() vs return()) Here's some modified code:
if(count(get_included_files()) ==1) exit("Direct access not permitted.");
The file being accessed is always an included file, hence the == 1.
1: Checking the count of included files
if( count(get_included_files()) == ((version_compare(PHP_VERSION, '5.0.0', '>='))?1:0) )
{
exit('Restricted Access');
}
Logic: PHP exits if the minimum include count isn't met. Note that prior to PHP5, the base page is not considered an include.
2: Defining and verifying a global constant
// In the base page (directly accessed):
define('_DEFVAR', 1);
// In the include files (where direct access isn't permitted):
defined('_DEFVAR') or exit('Restricted Access');
Logic: If the constant isn't defined, then the execution didn't start from the base page, and PHP would stop executing.
Note that for the sake of portability across upgrades and future changes, making this authentication method modular would significantly reduce the coding overhead as the changes won't need to be hard-coded to every single file.
// Put the code in a separate file instead, say 'checkdefined.php':
defined('_DEFVAR') or exit('Restricted Access');
// Replace the same code in the include files with:
require_once('checkdefined.php');
This way additional code can be added to checkdefined.php for logging and analytical purposes, as well as for generating appropriate responses.
Credit where credit is due: The brilliant idea of portability came from this answer. However there is one con to this method. Files in different folders may require different addresses to address this file. And server root based addressing may not work if you're running the current website from within a subfolder of the main site.
3: Remote address authorisation
// Call the include from the base page(directly accessed):
$includeData = file_get_contents("http://127.0.0.1/component.php?auth=token");
// In the include files (where direct access isn't permitted):
$src = $_SERVER['REMOTE_ADDR']; // Get the source address
$auth = authoriseIP($src); // Authorisation algorithm
if( !$auth ) exit('Restricted Access');
The drawback with this method is isolated execution, unless a session-token provided with the internal request. Verify via the loop-back address in case of a single server configuration, or an address white-list for a multi-server or load-balanced server infrastructure.
4: Token authorisation
Similar to the previous method, one can use GET or POST to pass an authorization token to the include file:
if($key!="serv97602"){header("Location: ".$dart);exit();}
A very messy method, but also perhaps the most secure and versatile at the same time, when used in the right way.
5: Webserver specific configuration
Most servers allow you to assign permissions for individual files or directories. You could place all your includes in such restricted directories, and have the server configured to deny them.
For example in APACHE, the configuration is stored in the .htaccess file. Tutorial here.
Note however that server-specific configurations are not recommended by me because they are bad for portability across different web-servers. In cases like Content Management Systems where the deny-algorithm is complex or the list of denied directories is rather big, it might only make reconfiguration sessions rather gruesome. In the end it's best to handle this in code.
6: Placing includes in a secure directory OUTSIDE the site root
Least preferred because of access limitations in server environments, but a rather powerful method if you have access to the file-system.
//Your secure dir path based on server file-system
$secure_dir=dirname($_SERVER['DOCUMENT_ROOT']).DIRECTORY_SEPARATOR."secure".DIRECTORY_SEPARATOR;
include($secure_dir."securepage.php");
Logic:
The user cannot request any file outside the htdocs folder as the links would be outside the scope of the website's address system.
The php server accesses the file-system natively, and hence can access files on a computer just like how a normal program with required privileges can.
By placing the include files in this directory, you can ensure that the php server gets to access them, while hotlinking is denied to the user.
Even if the webserver's filesystem access configuration wasn't done properly, this method would prevent those files from becoming public accidentally.
Please excuse my unorthodox coding conventions. Any feedback is appreciated.
The best way to prevent direct access to files is to place them outside of the web-server document root (usually, one level above). You can still include them, but there is no possibility of someone accessing them through an http request.
I usually go all the way, and place all of my PHP files outside of the document root aside from the bootstrap file - a lone index.php in the document root that starts routing the entire website/application.
An alternative (or complement) to Chuck's solution would be to deny access to files matching a specific pattern by putting something like this in your .htaccess file
<FilesMatch "\.(inc)$">
Order deny,allow
Deny from all
</FilesMatch>
Actually my advice is to do all of these best practices.
Put the documents outside the webroot OR in a directory denied access by the webserver
AND
Use a define in your visible documents that the hidden documents check for:
if (!defined(INCL_FILE_FOO)) {
header('HTTP/1.0 403 Forbidden');
exit;
}
This way if the files become misplaced somehow (an errant ftp operation) they are still protected.
I had this problem once, solved with:
if (strpos($_SERVER['REQUEST_URI'], basename(__FILE__)) !== false) ...
but the ideal solution is to place the file outside of the web-server document root, as mentioned in another anwser.
I wanted to restrict access to the PHP file directly, but also be able to call it via jQuery $.ajax (XMLHttpRequest). Here is what worked for me.
if (empty($_SERVER["HTTP_X_REQUESTED_WITH"]) && $_SERVER["HTTP_X_REQUESTED_WITH"] != "XMLHttpRequest") {
if (realpath($_SERVER["SCRIPT_FILENAME"]) == __FILE__) { // direct access denied
header("Location: /403");
exit;
}
}
You'd better build application with one entrance point, i.e. all files should be reached from index.php
Place this in index.php
define(A,true);
This check should run in each linked file (via require or include)
defined('A') or die(header('HTTP/1.0 403 Forbidden'));
debug_backtrace() || die ("Direct access not permitted");
My answer is somewhat different in approach but includes many of the answers provided here. I would recommend a multipronged approach:
.htaccess and Apache restrictions for sure
defined('_SOMECONSTANT') or die('Hackers! Be gone!');
HOWEVER the defined or die approach has a number of failings. Firstly, it is a real pain in the assumptions to test and debug with. Secondly, it involves horrifyingly, mind-numbingly boring refactoring if you change your mind. "Find and replace!" you say. Yes, but how sure are you that it is written exactly the same everywhere, hmmm? Now multiply that with thousands of files... o.O
And then there's .htaccess. What happens if your code is distributed onto sites where the administrator is not so scrupulous? If you rely only on .htaccess to secure your files you're also going to need a) a backup, b) a box of tissues to dry your tears, c) a fire extinguisher to put out the flames in all the hatemail from people using your code.
So I know the question asks for the "easiest", but I think what this calls for is more "defensive coding".
What I suggest is:
Before any of your scripts require('ifyoulieyougonnadie.php'); (not include() and as a replacement for defined or die)
In ifyoulieyougonnadie.php, do some logic stuff - check for different constants, calling script, localhost testing and such - and then implement your die(), throw new Exception, 403, etc.
I am creating my own framework with two possible entry points - the main index.php (Joomla framework) and ajaxrouter.php (my framework) - so depending on the point of entry, I check for different things. If the request to ifyoulieyougonnadie.php doesn't come from one of those two files, I know shenanigans are being undertaken!
But what if I add a new entry point? No worries. I just change ifyoulieyougonnadie.php and I'm sorted, plus no 'find and replace'. Hooray!
What if I decided to move some of my scripts to do a different framework that doesn't have the same constants defined()? ... Hooray! ^_^
I found this strategy makes development a lot more fun and a lot less:
/**
* Hmmm... why is my netbeans debugger only showing a blank white page
* for this script (that is being tested outside the framework)?
* Later... I just don't understand why my code is not working...
* Much later... There are no error messages or anything!
* Why is it not working!?!
* I HATE PHP!!!
*
* Scroll back to the top of my 100s of lines of code...
* U_U
*
* Sorry PHP. I didn't mean what I said. I was just upset.
*/
// defined('_JEXEC') or die();
class perfectlyWorkingCode {}
perfectlyWorkingCode::nowDoingStuffBecauseIRememberedToCommentOutTheDie();
The easiest way is to set some variable in the file that calls include, such as
$including = true;
Then in the file that's being included, check for the variable
if (!$including) exit("direct access not permitted");
Besides the .htaccess way, I have seen a useful pattern in various frameworks, for example in ruby on rails. They have a separate pub/ directory in the application root directory and the library directories are living in directories at the same level as pub/. Something like this (not ideal, but you get the idea):
app/
|
+--pub/
|
+--lib/
|
+--conf/
|
+--models/
|
+--views/
|
+--controllers/
You set up your web server to use pub/ as document root. This offers better protection to your scripts: while they can reach out from the document root to load necessary components it is impossible to access the components from the internet. Another benefit besides security is that everything is in one place.
This setup is better than just creating checks in every single included file because "access not permitted" message is a clue to attackers, and it is better than .htaccess configuration because it is not white-list based: if you screw up the file extensions it will not be visible in the lib/, conf/ etc. directories.
What Joomla! does is defining a Constant in a root file and checking if the same is defined in the included files.
defined('_JEXEC') or die('Restricted access');
or else
one can keep all files outside the reach of an http request by placing them outside the webroot directory as most frameworks like CodeIgniter recommend.
or even by placing an .htaccess file within the include folder and writing rules, you can prevent direct access.
<?php
$url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
if (false !== strpos($url,'.php')) {
die ("Direct access not premitted");
}
?>
If more precisely, you should use this condition:
if (array_search(__FILE__, get_included_files()) === 0) {
echo 'direct access';
}
else {
echo 'included';
}
get_included_files() returns indexed array containing names of all included files (if file is beign executed then it was included and its name is in the array).
So, when the file is directly accessed, its name is the first in the array, all other files in the array were included.
Storing your include files outside the web accessible directory has been mentioned a few times, and is certainly a good strategy where possible. However, another option I have not yet seen mentioned: ensure that your include files don’t contain any runnable code. If your include files merely define functions and classes, and have no code other than that, they will simply produce a blank page when accessed directly.
By all means allow direct access to this file from the browser: it won’t do anything. It defines some functions, but none of them are called, so none of them run.
<?php
function a() {
// function body
}
function b() {
// function body
}
The same applies to files which contain only PHP classes, and nothing else.
It’s still a good idea to keep your files outside of the web directory where possible.
You might accidentally deactivate PHP, in which case your server may send content of the PHP files to the browser, instead of running PHP and sending the result. This could result in your code (including database passwords, API keys, etc.) leaking.
Files in the web directory are squatting on URLs you may want to use for your app. I work with a CMS which cannot have a page called system, because that would conflict with a path used for code. I find this annoying.
Do something like:
<?php
if ($_SERVER['SCRIPT_FILENAME'] == '<path to php include file>') {
header('HTTP/1.0 403 Forbidden');
exit('Forbidden');
}
?>
<?php
if (eregi("YOUR_INCLUDED_PHP_FILE_NAME", $_SERVER['PHP_SELF'])) {
die("<h4>You don't have right permission to access this file directly.</h4>");
}
?>
place the code above in the top of your included php file.
ex:
<?php
if (eregi("some_functions.php", $_SERVER['PHP_SELF'])) {
die("<h4>You don't have right permission to access this file directly.</h4>");
}
// do something
?>
The following code is used in the Flatnux CMS (http://flatnux.altervista.org):
if ( strpos(strtolower($_SERVER['SCRIPT_NAME']),strtolower(basename(__FILE__))) )
{
header("Location: ../../index.php");
die("...");
}
I found this php-only and invariable solution which works both with http and cli :
Define a function :
function forbidDirectAccess($file) {
$self = getcwd()."/".trim($_SERVER["PHP_SELF"], "/");
(substr_compare($file, $self, -strlen($self)) != 0) or die('Restricted access');
}
Call the function in the file you want to prevent direct access to :
forbidDirectAccess(__FILE__);
Most of the solutions given above to this question do not work in Cli mode.
if (basename($_SERVER['PHP_SELF']) == basename(__FILE__)) { die('Access denied'); };
You can use the following method below although, it does have a flaw, because it can be faked, except if you can add another line of code to make sure the request comes only from your server either by using Javascript.
You can place this code in the Body section of your HTML code, so the error shows there.
<?
if(!isset($_SERVER['HTTP_REQUEST'])) { include ('error_file.php'); }
else { ?>
Place your other HTML code here
<? } ?>
End it like this, so the output of the error will always show within the body section, if that's how you want it to be.
i suggest that don't use of $_SERVER for security reasons .
You can use a variable like $root=true; in first file that included another one.
and use isset($root) in begin of second file that be included.
What you can also do is password protect the directory and keep all your php scripts in there, ofcourse except the index.php file, as at the time of include password won't be required as it will be required only for http access. what it will do is also provide you the option to access your scripts in case you want it as you will have password to access that directory. you will need to setup .htaccess file for the directory and a .htpasswd file to authenticate the user.
well, you can also use any of the solutions provided above in case you feel you don't need to access those files normally because you can always access them through cPanel etc.
Hope this helps
The easiest way is to store your includes outside of the web directory. That way the server has access to them but no outside machine. The only down side is you need to be able to access this part of your server. The upside is it requires no set up, configuration, or additional code/server stress.
I didn't find the suggestions with .htaccess so good because it may block
other content in that folder which you might want to allow user to access to,
this is my solution:
$currentFileInfo = pathinfo(__FILE__);
$requestInfo = pathinfo($_SERVER['REQUEST_URI']);
if($currentFileInfo['basename'] == $requestInfo['basename']){
// direct access to file
}
Earlier mentioned solution with PHP version check added:
$max_includes = version_compare(PHP_VERSION, '5', '<') ? 0 : 1;
if (count(get_included_files()) <= $max_includes)
{
exit('Direct access is not allowed.');
}
You can use phpMyAdmin Style:
/**
* block attempts to directly run this script
*/
if (getcwd() == dirname(__FILE__)) {
die('Attack stopped');
}

Php script to upload photos for single user and protect them [duplicate]

I have a php file which I will be using as exclusively as an include. Therefore I would like to throw an error instead of executing it when it's accessed directly by typing in the URL instead of being included.
Basically I need to do a check as follows in the php file:
if ( $REQUEST_URL == $URL_OF_CURRENT_PAGE ) die ("Direct access not premitted");
Is there an easy way to do this?
Add this to the page that you want to only be included
<?php
if(!defined('MyConst')) {
die('Direct access not permitted');
}
?>
then on the pages that include it add
<?php
define('MyConst', TRUE);
?>
The easiest way for the generic "PHP app running on an Apache server that you may or may not fully control" situation is to put your includes in a directory and deny access to that directory in your .htaccess file. To save people the trouble of Googling, if you're using Apache, put this in a file called ".htaccess" in the directory you don't want to be accessible:
Deny from all
If you actually have full control of the server (more common these days even for little apps than when I first wrote this answer), the best approach is to stick the files you want to protect outside of the directory that your web server is serving from. So if your app is in /srv/YourApp/, set the server to serve files from /srv/YourApp/app/ and put the includes in /srv/YourApp/includes, so there literally isn't any URL that can access them.
I have a file that I need to act differently when it's included vs when it's accessed directly (mainly a print() vs return()) Here's some modified code:
if(count(get_included_files()) ==1) exit("Direct access not permitted.");
The file being accessed is always an included file, hence the == 1.
1: Checking the count of included files
if( count(get_included_files()) == ((version_compare(PHP_VERSION, '5.0.0', '>='))?1:0) )
{
exit('Restricted Access');
}
Logic: PHP exits if the minimum include count isn't met. Note that prior to PHP5, the base page is not considered an include.
2: Defining and verifying a global constant
// In the base page (directly accessed):
define('_DEFVAR', 1);
// In the include files (where direct access isn't permitted):
defined('_DEFVAR') or exit('Restricted Access');
Logic: If the constant isn't defined, then the execution didn't start from the base page, and PHP would stop executing.
Note that for the sake of portability across upgrades and future changes, making this authentication method modular would significantly reduce the coding overhead as the changes won't need to be hard-coded to every single file.
// Put the code in a separate file instead, say 'checkdefined.php':
defined('_DEFVAR') or exit('Restricted Access');
// Replace the same code in the include files with:
require_once('checkdefined.php');
This way additional code can be added to checkdefined.php for logging and analytical purposes, as well as for generating appropriate responses.
Credit where credit is due: The brilliant idea of portability came from this answer. However there is one con to this method. Files in different folders may require different addresses to address this file. And server root based addressing may not work if you're running the current website from within a subfolder of the main site.
3: Remote address authorisation
// Call the include from the base page(directly accessed):
$includeData = file_get_contents("http://127.0.0.1/component.php?auth=token");
// In the include files (where direct access isn't permitted):
$src = $_SERVER['REMOTE_ADDR']; // Get the source address
$auth = authoriseIP($src); // Authorisation algorithm
if( !$auth ) exit('Restricted Access');
The drawback with this method is isolated execution, unless a session-token provided with the internal request. Verify via the loop-back address in case of a single server configuration, or an address white-list for a multi-server or load-balanced server infrastructure.
4: Token authorisation
Similar to the previous method, one can use GET or POST to pass an authorization token to the include file:
if($key!="serv97602"){header("Location: ".$dart);exit();}
A very messy method, but also perhaps the most secure and versatile at the same time, when used in the right way.
5: Webserver specific configuration
Most servers allow you to assign permissions for individual files or directories. You could place all your includes in such restricted directories, and have the server configured to deny them.
For example in APACHE, the configuration is stored in the .htaccess file. Tutorial here.
Note however that server-specific configurations are not recommended by me because they are bad for portability across different web-servers. In cases like Content Management Systems where the deny-algorithm is complex or the list of denied directories is rather big, it might only make reconfiguration sessions rather gruesome. In the end it's best to handle this in code.
6: Placing includes in a secure directory OUTSIDE the site root
Least preferred because of access limitations in server environments, but a rather powerful method if you have access to the file-system.
//Your secure dir path based on server file-system
$secure_dir=dirname($_SERVER['DOCUMENT_ROOT']).DIRECTORY_SEPARATOR."secure".DIRECTORY_SEPARATOR;
include($secure_dir."securepage.php");
Logic:
The user cannot request any file outside the htdocs folder as the links would be outside the scope of the website's address system.
The php server accesses the file-system natively, and hence can access files on a computer just like how a normal program with required privileges can.
By placing the include files in this directory, you can ensure that the php server gets to access them, while hotlinking is denied to the user.
Even if the webserver's filesystem access configuration wasn't done properly, this method would prevent those files from becoming public accidentally.
Please excuse my unorthodox coding conventions. Any feedback is appreciated.
The best way to prevent direct access to files is to place them outside of the web-server document root (usually, one level above). You can still include them, but there is no possibility of someone accessing them through an http request.
I usually go all the way, and place all of my PHP files outside of the document root aside from the bootstrap file - a lone index.php in the document root that starts routing the entire website/application.
An alternative (or complement) to Chuck's solution would be to deny access to files matching a specific pattern by putting something like this in your .htaccess file
<FilesMatch "\.(inc)$">
Order deny,allow
Deny from all
</FilesMatch>
Actually my advice is to do all of these best practices.
Put the documents outside the webroot OR in a directory denied access by the webserver
AND
Use a define in your visible documents that the hidden documents check for:
if (!defined(INCL_FILE_FOO)) {
header('HTTP/1.0 403 Forbidden');
exit;
}
This way if the files become misplaced somehow (an errant ftp operation) they are still protected.
I had this problem once, solved with:
if (strpos($_SERVER['REQUEST_URI'], basename(__FILE__)) !== false) ...
but the ideal solution is to place the file outside of the web-server document root, as mentioned in another anwser.
I wanted to restrict access to the PHP file directly, but also be able to call it via jQuery $.ajax (XMLHttpRequest). Here is what worked for me.
if (empty($_SERVER["HTTP_X_REQUESTED_WITH"]) && $_SERVER["HTTP_X_REQUESTED_WITH"] != "XMLHttpRequest") {
if (realpath($_SERVER["SCRIPT_FILENAME"]) == __FILE__) { // direct access denied
header("Location: /403");
exit;
}
}
You'd better build application with one entrance point, i.e. all files should be reached from index.php
Place this in index.php
define(A,true);
This check should run in each linked file (via require or include)
defined('A') or die(header('HTTP/1.0 403 Forbidden'));
debug_backtrace() || die ("Direct access not permitted");
My answer is somewhat different in approach but includes many of the answers provided here. I would recommend a multipronged approach:
.htaccess and Apache restrictions for sure
defined('_SOMECONSTANT') or die('Hackers! Be gone!');
HOWEVER the defined or die approach has a number of failings. Firstly, it is a real pain in the assumptions to test and debug with. Secondly, it involves horrifyingly, mind-numbingly boring refactoring if you change your mind. "Find and replace!" you say. Yes, but how sure are you that it is written exactly the same everywhere, hmmm? Now multiply that with thousands of files... o.O
And then there's .htaccess. What happens if your code is distributed onto sites where the administrator is not so scrupulous? If you rely only on .htaccess to secure your files you're also going to need a) a backup, b) a box of tissues to dry your tears, c) a fire extinguisher to put out the flames in all the hatemail from people using your code.
So I know the question asks for the "easiest", but I think what this calls for is more "defensive coding".
What I suggest is:
Before any of your scripts require('ifyoulieyougonnadie.php'); (not include() and as a replacement for defined or die)
In ifyoulieyougonnadie.php, do some logic stuff - check for different constants, calling script, localhost testing and such - and then implement your die(), throw new Exception, 403, etc.
I am creating my own framework with two possible entry points - the main index.php (Joomla framework) and ajaxrouter.php (my framework) - so depending on the point of entry, I check for different things. If the request to ifyoulieyougonnadie.php doesn't come from one of those two files, I know shenanigans are being undertaken!
But what if I add a new entry point? No worries. I just change ifyoulieyougonnadie.php and I'm sorted, plus no 'find and replace'. Hooray!
What if I decided to move some of my scripts to do a different framework that doesn't have the same constants defined()? ... Hooray! ^_^
I found this strategy makes development a lot more fun and a lot less:
/**
* Hmmm... why is my netbeans debugger only showing a blank white page
* for this script (that is being tested outside the framework)?
* Later... I just don't understand why my code is not working...
* Much later... There are no error messages or anything!
* Why is it not working!?!
* I HATE PHP!!!
*
* Scroll back to the top of my 100s of lines of code...
* U_U
*
* Sorry PHP. I didn't mean what I said. I was just upset.
*/
// defined('_JEXEC') or die();
class perfectlyWorkingCode {}
perfectlyWorkingCode::nowDoingStuffBecauseIRememberedToCommentOutTheDie();
The easiest way is to set some variable in the file that calls include, such as
$including = true;
Then in the file that's being included, check for the variable
if (!$including) exit("direct access not permitted");
Besides the .htaccess way, I have seen a useful pattern in various frameworks, for example in ruby on rails. They have a separate pub/ directory in the application root directory and the library directories are living in directories at the same level as pub/. Something like this (not ideal, but you get the idea):
app/
|
+--pub/
|
+--lib/
|
+--conf/
|
+--models/
|
+--views/
|
+--controllers/
You set up your web server to use pub/ as document root. This offers better protection to your scripts: while they can reach out from the document root to load necessary components it is impossible to access the components from the internet. Another benefit besides security is that everything is in one place.
This setup is better than just creating checks in every single included file because "access not permitted" message is a clue to attackers, and it is better than .htaccess configuration because it is not white-list based: if you screw up the file extensions it will not be visible in the lib/, conf/ etc. directories.
What Joomla! does is defining a Constant in a root file and checking if the same is defined in the included files.
defined('_JEXEC') or die('Restricted access');
or else
one can keep all files outside the reach of an http request by placing them outside the webroot directory as most frameworks like CodeIgniter recommend.
or even by placing an .htaccess file within the include folder and writing rules, you can prevent direct access.
<?php
$url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
if (false !== strpos($url,'.php')) {
die ("Direct access not premitted");
}
?>
If more precisely, you should use this condition:
if (array_search(__FILE__, get_included_files()) === 0) {
echo 'direct access';
}
else {
echo 'included';
}
get_included_files() returns indexed array containing names of all included files (if file is beign executed then it was included and its name is in the array).
So, when the file is directly accessed, its name is the first in the array, all other files in the array were included.
Storing your include files outside the web accessible directory has been mentioned a few times, and is certainly a good strategy where possible. However, another option I have not yet seen mentioned: ensure that your include files don’t contain any runnable code. If your include files merely define functions and classes, and have no code other than that, they will simply produce a blank page when accessed directly.
By all means allow direct access to this file from the browser: it won’t do anything. It defines some functions, but none of them are called, so none of them run.
<?php
function a() {
// function body
}
function b() {
// function body
}
The same applies to files which contain only PHP classes, and nothing else.
It’s still a good idea to keep your files outside of the web directory where possible.
You might accidentally deactivate PHP, in which case your server may send content of the PHP files to the browser, instead of running PHP and sending the result. This could result in your code (including database passwords, API keys, etc.) leaking.
Files in the web directory are squatting on URLs you may want to use for your app. I work with a CMS which cannot have a page called system, because that would conflict with a path used for code. I find this annoying.
Do something like:
<?php
if ($_SERVER['SCRIPT_FILENAME'] == '<path to php include file>') {
header('HTTP/1.0 403 Forbidden');
exit('Forbidden');
}
?>
<?php
if (eregi("YOUR_INCLUDED_PHP_FILE_NAME", $_SERVER['PHP_SELF'])) {
die("<h4>You don't have right permission to access this file directly.</h4>");
}
?>
place the code above in the top of your included php file.
ex:
<?php
if (eregi("some_functions.php", $_SERVER['PHP_SELF'])) {
die("<h4>You don't have right permission to access this file directly.</h4>");
}
// do something
?>
The following code is used in the Flatnux CMS (http://flatnux.altervista.org):
if ( strpos(strtolower($_SERVER['SCRIPT_NAME']),strtolower(basename(__FILE__))) )
{
header("Location: ../../index.php");
die("...");
}
I found this php-only and invariable solution which works both with http and cli :
Define a function :
function forbidDirectAccess($file) {
$self = getcwd()."/".trim($_SERVER["PHP_SELF"], "/");
(substr_compare($file, $self, -strlen($self)) != 0) or die('Restricted access');
}
Call the function in the file you want to prevent direct access to :
forbidDirectAccess(__FILE__);
Most of the solutions given above to this question do not work in Cli mode.
if (basename($_SERVER['PHP_SELF']) == basename(__FILE__)) { die('Access denied'); };
You can use the following method below although, it does have a flaw, because it can be faked, except if you can add another line of code to make sure the request comes only from your server either by using Javascript.
You can place this code in the Body section of your HTML code, so the error shows there.
<?
if(!isset($_SERVER['HTTP_REQUEST'])) { include ('error_file.php'); }
else { ?>
Place your other HTML code here
<? } ?>
End it like this, so the output of the error will always show within the body section, if that's how you want it to be.
i suggest that don't use of $_SERVER for security reasons .
You can use a variable like $root=true; in first file that included another one.
and use isset($root) in begin of second file that be included.
What you can also do is password protect the directory and keep all your php scripts in there, ofcourse except the index.php file, as at the time of include password won't be required as it will be required only for http access. what it will do is also provide you the option to access your scripts in case you want it as you will have password to access that directory. you will need to setup .htaccess file for the directory and a .htpasswd file to authenticate the user.
well, you can also use any of the solutions provided above in case you feel you don't need to access those files normally because you can always access them through cPanel etc.
Hope this helps
The easiest way is to store your includes outside of the web directory. That way the server has access to them but no outside machine. The only down side is you need to be able to access this part of your server. The upside is it requires no set up, configuration, or additional code/server stress.
I didn't find the suggestions with .htaccess so good because it may block
other content in that folder which you might want to allow user to access to,
this is my solution:
$currentFileInfo = pathinfo(__FILE__);
$requestInfo = pathinfo($_SERVER['REQUEST_URI']);
if($currentFileInfo['basename'] == $requestInfo['basename']){
// direct access to file
}
Earlier mentioned solution with PHP version check added:
$max_includes = version_compare(PHP_VERSION, '5', '<') ? 0 : 1;
if (count(get_included_files()) <= $max_includes)
{
exit('Direct access is not allowed.');
}
You can use phpMyAdmin Style:
/**
* block attempts to directly run this script
*/
if (getcwd() == dirname(__FILE__)) {
die('Attack stopped');
}

Application Entrypoint

I'm building an application and using index.php as and entry point to different modules. I noticed SugarCRM does this and it appears like a good idea.
The URL Looks like this
http://www.mypage.com/index.php?mod=log&pag=login
Where mod is the module and pag is the page
The index.php looks line this:
<?PHP
define('INCLUDE_CHECK',true);
// Class Loader
require ('app/inc/app_autoload.php');
// HTML Header with js and css links
require ('header.php');
// Content Page
$url_module = $_GET["mod"];
$url_page = $_GET["pag"];
$content = $url_module."/".$url_page.".php";
// For the above URL $content = log/login.php
if (!file_exists ($content)) {
require ($content);
}else{
// Handle Error
}
// Footer
require ('footer.php');
?>
Is this safe?
If it's safe, Is it in line with practices?
This can be potentially unsafe. Depends on all the other PHP files that PHP can open. If all of them are class files that don't execute anything, then you're safe. However, if any of them execute something automatically...maybe not.
Let's say that you have PHP files inside a folder:
/secured/file.php
And let's say that the folder has an .htaccess that prohibits anyone from navigating to the page directly. Or better, let's say it's above your root directory. However, the hacker sends "../secured" as the value of mod and "file" as the value of page. In such a case, PHP may allow the person to include that file, and if it self-executes, it may have unintended consequences.
This is why Zend Framework requires explicit configuration of all MVC paths. Other frameworks allow for a some dynamic inclusion, but they often do something like append "Controller.php" to the end of the string, which ensures that the file included must be a Controller...and thus intended to be included in such a way.
When it comes to security, the best thing you can do is make sure that YOU...with all the knowledge of the entire server...can't open up any file that you don't want to be opened by someone else. If you can't get the code to do it, knowing what files are there, then you have implemented some decent (though likely still not flawless) security.

How to secure admin folder php

I am looking to find a way I can secure admin area, especially the folder itself from outside access (These include folders with images and css). I have read a lot of suggestions but they all feel rather a compromise or work around than a bullet proof method or I am not understanding which is best for security and hidden from outside world, I want to be the only one that knows about it or access it. Hoping someone can shed some light what they would use, when they want the area completely hidden from outside world, whilst still accessible to you.
Some of the methods I have come across involve:
Moving folder outside of root
Using Htaccess Deny all. (also means I can't login unless I apply a static IP address which I do not have)
Another way I thought of could be to use session variable to store admin, recognize and grant access based on session ID. (This does mean all other css files and image folders are viewable).
Adding an index page in the folder which I see alot of sites do.
I currently have my login script to redirect me to my admin area, so is there anyway for the whole folder to recognize it's me and grant access and serve files on if a logged in admin php file is requesting it?, if not to decline access including images and css etc?
Can't figure out how best to protect this area? Is using session a secure way of identifying an admin?
The easiest way to ensure content is not exposed to the web is to place it above the site folder in your directory structure.
so for example in your Apache configuration mount the site at
/var/www/sites/site/content/
and place the restricted content at
/var/www/sites/site/
that way the content will not be exposed but php can still read it if required.
Obviously this will not stop users from seeing what is in your css files if php reads them and echoes them out but I dont see why a css file should need to be secure
Edit
Supposing you have a folder on your server at /var/www/sites/site/content/some_folder
and you enter www.yoursite.com/some_folder into a browser, assuming you have indexes open in your site you will see a list of files in some_folder
But how can you get to /var/www/sites/site/ from a web brower ? ... you can't!!
but what you can do is some thing like this:
And this would be a php file inside the main site folder (visible to public)
<?php
session_start();
if(isset($_SESSION['admin_logged_in'])){
include '/var/www/sites/site/secret_content.php';
}
The first step would indeed be to move all files you want to prevent public access to to outside the document root. This way there is no way to access the files directly through your webserver.
If you are looking to prevent access for all resources (including images, scripts, stylesheets etc) you could implement a "proxy" which is responsible for serving the files (after checking whether the user is authorized).
The easiest and most flexible way to do this is to have a single entry point in the application. Using apache this can easily be achieved using the following rewrite rule:
RewriteEngine On
RewriteRule ^(.*)$ index.php [L,QSA]
This will make sure every request will go through your index.php file.
No you can easiy check whether you are allowed to access the resources using e.g.:
<?php
session_start();
if (!isset($_SESSION['user'])) {
header('HTTP/1.0 403 Forbidden');
exit; // important to prevent further execution of the script
}
// user is allowed access, do shit
The above is a very simplified example. Normally you may want to render an actual nice looking page telling the user he is not allowed to access you stuff / rendering a login page.
Now to render the protected resources you could do something like:
Directory structure
Project
public (docroot)
index.php
index.php
other protected files
index.php in docroot
<?php
require_once __DIR__ . '/../index.php';
index.php in project
<?php
session_start();
if (!isset($_SESSION['user'])) {
header('HTTP/1.0 403 Forbidden');
exit; // important to prevent further execution of the script
}
$file = $_SERVER['REQUEST_URI']; // important to sanitize or possible check against whitelist the requested resource
$ext = pathinfo($path, PATHINFO_EXTENSION);
switch ($ext) {
case 'jpg':
case 'jpeg':
header('Content-type: image/jpeg');
imagejpeg('/path/to/protected/resources/' . $file);
break;
}
Now you will lhave total control over what you serve and to whom.
Note that whether it is secure depends entirely on what your implementation looks like, but in general:
Always place your non public files outside of the document root
Always sanitize / whitelist user input
Always secure your data
Some generic, but related reads:
Preventing Directory Traversal in PHP but allowing paths (very much related to the $file = $_SERVER['REQUEST_URI']; point)
How can I prevent SQL-injection in PHP?
Secure hash and salt for PHP passwords
Yes, you should move the content out of the document root. You could try using .htaccess to protect your files, but allowing overrides by .htaccess can itself be a security problem. It's certainly a performance problem.
Simply point your 404 handler at something like....
<?php
define('REQUEST_PATH', '/secure');
define('SECURED_CONTENT', '/var/www/restricted');
$req=parse_url($_SERVER["REQUEST_URI"]);
if ((0===strpos($req['path'],REQUEST_PATH))
&& $_SESSION['authenticated']) {
if (is_readable(SECURED_CONTENT . $req['path'])
&& is_file(SECURED_CONTENT . $req['path'])) {
header('Content-type: '
. mime_content_type(SECURED_CONTENT . $req['path']);
include(SECURED_CONTENT . $req_path);
} else {
header('HTTP/1.0 404 Not Found');
}
exit;
}
header('HTTP/1.0 403 Forbidden');

Prevent direct access to a php include file

I have a php file which I will be using as exclusively as an include. Therefore I would like to throw an error instead of executing it when it's accessed directly by typing in the URL instead of being included.
Basically I need to do a check as follows in the php file:
if ( $REQUEST_URL == $URL_OF_CURRENT_PAGE ) die ("Direct access not premitted");
Is there an easy way to do this?
Add this to the page that you want to only be included
<?php
if(!defined('MyConst')) {
die('Direct access not permitted');
}
?>
then on the pages that include it add
<?php
define('MyConst', TRUE);
?>
The easiest way for the generic "PHP app running on an Apache server that you may or may not fully control" situation is to put your includes in a directory and deny access to that directory in your .htaccess file. To save people the trouble of Googling, if you're using Apache, put this in a file called ".htaccess" in the directory you don't want to be accessible:
Deny from all
If you actually have full control of the server (more common these days even for little apps than when I first wrote this answer), the best approach is to stick the files you want to protect outside of the directory that your web server is serving from. So if your app is in /srv/YourApp/, set the server to serve files from /srv/YourApp/app/ and put the includes in /srv/YourApp/includes, so there literally isn't any URL that can access them.
I have a file that I need to act differently when it's included vs when it's accessed directly (mainly a print() vs return()) Here's some modified code:
if(count(get_included_files()) ==1) exit("Direct access not permitted.");
The file being accessed is always an included file, hence the == 1.
1: Checking the count of included files
if( count(get_included_files()) == ((version_compare(PHP_VERSION, '5.0.0', '>='))?1:0) )
{
exit('Restricted Access');
}
Logic: PHP exits if the minimum include count isn't met. Note that prior to PHP5, the base page is not considered an include.
2: Defining and verifying a global constant
// In the base page (directly accessed):
define('_DEFVAR', 1);
// In the include files (where direct access isn't permitted):
defined('_DEFVAR') or exit('Restricted Access');
Logic: If the constant isn't defined, then the execution didn't start from the base page, and PHP would stop executing.
Note that for the sake of portability across upgrades and future changes, making this authentication method modular would significantly reduce the coding overhead as the changes won't need to be hard-coded to every single file.
// Put the code in a separate file instead, say 'checkdefined.php':
defined('_DEFVAR') or exit('Restricted Access');
// Replace the same code in the include files with:
require_once('checkdefined.php');
This way additional code can be added to checkdefined.php for logging and analytical purposes, as well as for generating appropriate responses.
Credit where credit is due: The brilliant idea of portability came from this answer. However there is one con to this method. Files in different folders may require different addresses to address this file. And server root based addressing may not work if you're running the current website from within a subfolder of the main site.
3: Remote address authorisation
// Call the include from the base page(directly accessed):
$includeData = file_get_contents("http://127.0.0.1/component.php?auth=token");
// In the include files (where direct access isn't permitted):
$src = $_SERVER['REMOTE_ADDR']; // Get the source address
$auth = authoriseIP($src); // Authorisation algorithm
if( !$auth ) exit('Restricted Access');
The drawback with this method is isolated execution, unless a session-token provided with the internal request. Verify via the loop-back address in case of a single server configuration, or an address white-list for a multi-server or load-balanced server infrastructure.
4: Token authorisation
Similar to the previous method, one can use GET or POST to pass an authorization token to the include file:
if($key!="serv97602"){header("Location: ".$dart);exit();}
A very messy method, but also perhaps the most secure and versatile at the same time, when used in the right way.
5: Webserver specific configuration
Most servers allow you to assign permissions for individual files or directories. You could place all your includes in such restricted directories, and have the server configured to deny them.
For example in APACHE, the configuration is stored in the .htaccess file. Tutorial here.
Note however that server-specific configurations are not recommended by me because they are bad for portability across different web-servers. In cases like Content Management Systems where the deny-algorithm is complex or the list of denied directories is rather big, it might only make reconfiguration sessions rather gruesome. In the end it's best to handle this in code.
6: Placing includes in a secure directory OUTSIDE the site root
Least preferred because of access limitations in server environments, but a rather powerful method if you have access to the file-system.
//Your secure dir path based on server file-system
$secure_dir=dirname($_SERVER['DOCUMENT_ROOT']).DIRECTORY_SEPARATOR."secure".DIRECTORY_SEPARATOR;
include($secure_dir."securepage.php");
Logic:
The user cannot request any file outside the htdocs folder as the links would be outside the scope of the website's address system.
The php server accesses the file-system natively, and hence can access files on a computer just like how a normal program with required privileges can.
By placing the include files in this directory, you can ensure that the php server gets to access them, while hotlinking is denied to the user.
Even if the webserver's filesystem access configuration wasn't done properly, this method would prevent those files from becoming public accidentally.
Please excuse my unorthodox coding conventions. Any feedback is appreciated.
The best way to prevent direct access to files is to place them outside of the web-server document root (usually, one level above). You can still include them, but there is no possibility of someone accessing them through an http request.
I usually go all the way, and place all of my PHP files outside of the document root aside from the bootstrap file - a lone index.php in the document root that starts routing the entire website/application.
An alternative (or complement) to Chuck's solution would be to deny access to files matching a specific pattern by putting something like this in your .htaccess file
<FilesMatch "\.(inc)$">
Order deny,allow
Deny from all
</FilesMatch>
Actually my advice is to do all of these best practices.
Put the documents outside the webroot OR in a directory denied access by the webserver
AND
Use a define in your visible documents that the hidden documents check for:
if (!defined(INCL_FILE_FOO)) {
header('HTTP/1.0 403 Forbidden');
exit;
}
This way if the files become misplaced somehow (an errant ftp operation) they are still protected.
I had this problem once, solved with:
if (strpos($_SERVER['REQUEST_URI'], basename(__FILE__)) !== false) ...
but the ideal solution is to place the file outside of the web-server document root, as mentioned in another anwser.
I wanted to restrict access to the PHP file directly, but also be able to call it via jQuery $.ajax (XMLHttpRequest). Here is what worked for me.
if (empty($_SERVER["HTTP_X_REQUESTED_WITH"]) && $_SERVER["HTTP_X_REQUESTED_WITH"] != "XMLHttpRequest") {
if (realpath($_SERVER["SCRIPT_FILENAME"]) == __FILE__) { // direct access denied
header("Location: /403");
exit;
}
}
You'd better build application with one entrance point, i.e. all files should be reached from index.php
Place this in index.php
define(A,true);
This check should run in each linked file (via require or include)
defined('A') or die(header('HTTP/1.0 403 Forbidden'));
debug_backtrace() || die ("Direct access not permitted");
My answer is somewhat different in approach but includes many of the answers provided here. I would recommend a multipronged approach:
.htaccess and Apache restrictions for sure
defined('_SOMECONSTANT') or die('Hackers! Be gone!');
HOWEVER the defined or die approach has a number of failings. Firstly, it is a real pain in the assumptions to test and debug with. Secondly, it involves horrifyingly, mind-numbingly boring refactoring if you change your mind. "Find and replace!" you say. Yes, but how sure are you that it is written exactly the same everywhere, hmmm? Now multiply that with thousands of files... o.O
And then there's .htaccess. What happens if your code is distributed onto sites where the administrator is not so scrupulous? If you rely only on .htaccess to secure your files you're also going to need a) a backup, b) a box of tissues to dry your tears, c) a fire extinguisher to put out the flames in all the hatemail from people using your code.
So I know the question asks for the "easiest", but I think what this calls for is more "defensive coding".
What I suggest is:
Before any of your scripts require('ifyoulieyougonnadie.php'); (not include() and as a replacement for defined or die)
In ifyoulieyougonnadie.php, do some logic stuff - check for different constants, calling script, localhost testing and such - and then implement your die(), throw new Exception, 403, etc.
I am creating my own framework with two possible entry points - the main index.php (Joomla framework) and ajaxrouter.php (my framework) - so depending on the point of entry, I check for different things. If the request to ifyoulieyougonnadie.php doesn't come from one of those two files, I know shenanigans are being undertaken!
But what if I add a new entry point? No worries. I just change ifyoulieyougonnadie.php and I'm sorted, plus no 'find and replace'. Hooray!
What if I decided to move some of my scripts to do a different framework that doesn't have the same constants defined()? ... Hooray! ^_^
I found this strategy makes development a lot more fun and a lot less:
/**
* Hmmm... why is my netbeans debugger only showing a blank white page
* for this script (that is being tested outside the framework)?
* Later... I just don't understand why my code is not working...
* Much later... There are no error messages or anything!
* Why is it not working!?!
* I HATE PHP!!!
*
* Scroll back to the top of my 100s of lines of code...
* U_U
*
* Sorry PHP. I didn't mean what I said. I was just upset.
*/
// defined('_JEXEC') or die();
class perfectlyWorkingCode {}
perfectlyWorkingCode::nowDoingStuffBecauseIRememberedToCommentOutTheDie();
The easiest way is to set some variable in the file that calls include, such as
$including = true;
Then in the file that's being included, check for the variable
if (!$including) exit("direct access not permitted");
Besides the .htaccess way, I have seen a useful pattern in various frameworks, for example in ruby on rails. They have a separate pub/ directory in the application root directory and the library directories are living in directories at the same level as pub/. Something like this (not ideal, but you get the idea):
app/
|
+--pub/
|
+--lib/
|
+--conf/
|
+--models/
|
+--views/
|
+--controllers/
You set up your web server to use pub/ as document root. This offers better protection to your scripts: while they can reach out from the document root to load necessary components it is impossible to access the components from the internet. Another benefit besides security is that everything is in one place.
This setup is better than just creating checks in every single included file because "access not permitted" message is a clue to attackers, and it is better than .htaccess configuration because it is not white-list based: if you screw up the file extensions it will not be visible in the lib/, conf/ etc. directories.
What Joomla! does is defining a Constant in a root file and checking if the same is defined in the included files.
defined('_JEXEC') or die('Restricted access');
or else
one can keep all files outside the reach of an http request by placing them outside the webroot directory as most frameworks like CodeIgniter recommend.
or even by placing an .htaccess file within the include folder and writing rules, you can prevent direct access.
<?php
$url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
if (false !== strpos($url,'.php')) {
die ("Direct access not premitted");
}
?>
If more precisely, you should use this condition:
if (array_search(__FILE__, get_included_files()) === 0) {
echo 'direct access';
}
else {
echo 'included';
}
get_included_files() returns indexed array containing names of all included files (if file is beign executed then it was included and its name is in the array).
So, when the file is directly accessed, its name is the first in the array, all other files in the array were included.
Storing your include files outside the web accessible directory has been mentioned a few times, and is certainly a good strategy where possible. However, another option I have not yet seen mentioned: ensure that your include files don’t contain any runnable code. If your include files merely define functions and classes, and have no code other than that, they will simply produce a blank page when accessed directly.
By all means allow direct access to this file from the browser: it won’t do anything. It defines some functions, but none of them are called, so none of them run.
<?php
function a() {
// function body
}
function b() {
// function body
}
The same applies to files which contain only PHP classes, and nothing else.
It’s still a good idea to keep your files outside of the web directory where possible.
You might accidentally deactivate PHP, in which case your server may send content of the PHP files to the browser, instead of running PHP and sending the result. This could result in your code (including database passwords, API keys, etc.) leaking.
Files in the web directory are squatting on URLs you may want to use for your app. I work with a CMS which cannot have a page called system, because that would conflict with a path used for code. I find this annoying.
Do something like:
<?php
if ($_SERVER['SCRIPT_FILENAME'] == '<path to php include file>') {
header('HTTP/1.0 403 Forbidden');
exit('Forbidden');
}
?>
<?php
if (eregi("YOUR_INCLUDED_PHP_FILE_NAME", $_SERVER['PHP_SELF'])) {
die("<h4>You don't have right permission to access this file directly.</h4>");
}
?>
place the code above in the top of your included php file.
ex:
<?php
if (eregi("some_functions.php", $_SERVER['PHP_SELF'])) {
die("<h4>You don't have right permission to access this file directly.</h4>");
}
// do something
?>
The following code is used in the Flatnux CMS (http://flatnux.altervista.org):
if ( strpos(strtolower($_SERVER['SCRIPT_NAME']),strtolower(basename(__FILE__))) )
{
header("Location: ../../index.php");
die("...");
}
I found this php-only and invariable solution which works both with http and cli :
Define a function :
function forbidDirectAccess($file) {
$self = getcwd()."/".trim($_SERVER["PHP_SELF"], "/");
(substr_compare($file, $self, -strlen($self)) != 0) or die('Restricted access');
}
Call the function in the file you want to prevent direct access to :
forbidDirectAccess(__FILE__);
Most of the solutions given above to this question do not work in Cli mode.
if (basename($_SERVER['PHP_SELF']) == basename(__FILE__)) { die('Access denied'); };
You can use the following method below although, it does have a flaw, because it can be faked, except if you can add another line of code to make sure the request comes only from your server either by using Javascript.
You can place this code in the Body section of your HTML code, so the error shows there.
<?
if(!isset($_SERVER['HTTP_REQUEST'])) { include ('error_file.php'); }
else { ?>
Place your other HTML code here
<? } ?>
End it like this, so the output of the error will always show within the body section, if that's how you want it to be.
i suggest that don't use of $_SERVER for security reasons .
You can use a variable like $root=true; in first file that included another one.
and use isset($root) in begin of second file that be included.
What you can also do is password protect the directory and keep all your php scripts in there, ofcourse except the index.php file, as at the time of include password won't be required as it will be required only for http access. what it will do is also provide you the option to access your scripts in case you want it as you will have password to access that directory. you will need to setup .htaccess file for the directory and a .htpasswd file to authenticate the user.
well, you can also use any of the solutions provided above in case you feel you don't need to access those files normally because you can always access them through cPanel etc.
Hope this helps
The easiest way is to store your includes outside of the web directory. That way the server has access to them but no outside machine. The only down side is you need to be able to access this part of your server. The upside is it requires no set up, configuration, or additional code/server stress.
I didn't find the suggestions with .htaccess so good because it may block
other content in that folder which you might want to allow user to access to,
this is my solution:
$currentFileInfo = pathinfo(__FILE__);
$requestInfo = pathinfo($_SERVER['REQUEST_URI']);
if($currentFileInfo['basename'] == $requestInfo['basename']){
// direct access to file
}
Earlier mentioned solution with PHP version check added:
$max_includes = version_compare(PHP_VERSION, '5', '<') ? 0 : 1;
if (count(get_included_files()) <= $max_includes)
{
exit('Direct access is not allowed.');
}
You can use phpMyAdmin Style:
/**
* block attempts to directly run this script
*/
if (getcwd() == dirname(__FILE__)) {
die('Attack stopped');
}

Categories