防止直接访问php包含文件

我有一个PHP文件,我将作为一个包括使用。 因此,我想抛出一个错误,而不是执行它时,直接通过inputURL而不是被包括在内。

基本上我需要在php文件中进行如下检查:

if ( $REQUEST_URL == $URL_OF_CURRENT_PAGE ) die ("Direct access not premitted"); 

是否有捷径可寻?

在Apache服务器上运行的通用“PHP应用程序可能或不可能完全控制”情况的最简单方法是将你的包放在一个目录中,并且拒绝你的.htaccess文件中的那个目录的访问。 为了节省人们search谷歌的麻烦,如果您使用的是Apache,请将其放在您不想访问的目录中的“.htaccess”文件中:

 Deny from all 

如果你实际上已经完全控制了服务器(即使对于小应用程序来说,这些日子也比我第一次写这个答案的时候更常见),最好的方法是把你想保护的文件粘贴在Web服务器所服务的目录之外。 因此,如果您的应用程序位于/srv/YourApp/ ,请将服务器设置为从/srv/YourApp/app/提供文件,并将其包含在/srv/YourApp/includes ,因此从字面上看,没有任何URL可以访问它们。

将此添加到您只希望包含的页面中

 <?php if(!defined('MyConst')) { die('Direct access not permitted'); } ?> 

然后在包含它的页面上添加

 <?php define('MyConst', TRUE); ?> 

我有一个文件,我需要采取不同的行为,当它被包括与直接访问(主要是一个print() vs return() )这里有一些修改后的代码:

 if(count(get_included_files()) ==1) exit("Direct access not permitted."); 

被访问的文件总是一个包含文件,因此== 1。

防止直接访问文件的最好方法是将它们放在Web服务器文档根目录之外(通常是上面的一个级别)。 您仍然可以包含它们,但是没有人通过http请求访问它们。

我通常会一路走下去,把所有的PHP文件放在文档根目录以外的引导文件之外 – 文档根目录中的一个独立的index.php,它开始路由整个网站/应用程序。

查克的解决scheme的替代(或补充)将是拒绝访问匹配特定模式的文件,通过在你的.htaccess文件

 <FilesMatch "\.(inc)$"> Order deny,allow Deny from all </FilesMatch> 

其实我的build议是做所有这些最佳做法。

  • 将文档放在webroot或OR之外的Web服务器AND拒绝访问的目录中
  • 在可见文档中使用一个定义,隐藏的文档检查:
  if (!defined(INCL_FILE_FOO)) { header('HTTP/1.0 403 Forbidden'); exit; } 

这样,如果文件变得错位(一个错误的FTP操作),他们仍然受到保护。

方法1:

检查包括计数

 if( count(get_included_files()) == ((version_compare(PHP_VERSION, '5.0.0', '>='))?1:0) ) { exit(); } 

逻辑:

  • PHP5 +:检查> = 1
  • 其他:检查> = 0
  • 否则:退出()

PHP5 +也将当前页面视为包含。


方法2:

使用授权的前端地址

这在用户可以直接访问的main.php文件中进行:

 $loopbackdata=file_get_contents("http://127.0.0.1/component.php?query=string"); 

其中component.php是您不希望用户直接访问的文件。


在你的component.php文件上面,你可以使用:

 //VARS $dart="/error.php?errortype=direct_access_of_component"; //Description: Direct-Access Redirection Target //GET SOURCE OF REQUEST $src=$_SERVER['REMOTE_ADDR']; //VALIDATE SOURCE(COMPARE AGAINST AUTHORIZED FRONT-END SERVER ADDRESSES) $auth=false; switch($src){ case "localhost": case "127.0.0.1": case "192.168.0.1": $auth=true; break; default: $auth=false; } //IF NOT AUTHENTICATED, EXIT: if(!$auth){header("Location: ".$dart);exit();} //ELSE PROCEED WITH CODE 

方法3:

使用GET或POST查询将授权密钥传递给'component.php'

使用phpparsingstring。 最后,

 if($key!="serv97602"){header("Location: ".$dart);exit();} 

这种方法可能用于访问PHP-include文件是有条件的,可能是基于会话或授权级别。 一个非常混乱的方法,但也可能是最安全和多function的同时,以正确的方式使用。


方法4:

Webserver特定的configuration

大多数服务器允许您为单个文件或目录分配权限。 您可以将所有包含在这些受限制的目录中,并将服务器configuration为拒绝它们。

例如,在APACHE中,configuration存储在.htaccess文件中。 这里的教程。

请注意 ,服务器特定的configuration不是我推荐的,因为它们不利于跨不同的Web服务器的可移植性。 在这种情况下,拒绝algorithm很复杂,或者被拒绝的目录列表比较大,可能只会使重新configuration会话变得相当可怕。 最后,最好在代码中处理这个问题。


方法5:

放置包含在网站根目录外的安全目录中

由于服务器环境中的访问限制,最不推荐使用这种方法,但如果您有权访问文件系统,则使用相当强大的方法。

 //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"); 

逻辑:

  • 用户不能请求htdocs文件夹以外的任何文件,因为链接将超出网站地址系统的范围。
  • PHP服务器本地访问文件系统,因此可以访问计算机上的文件,就像具有所需特权的普通程序一样。
  • 通过将include文件放在这个目录中,你可以确保php服务器能够访问它们,而盗链的情况则会被拒绝。

请原谅我糟糕的编码习惯。 我不是一个经验丰富的PHP开发人员。 那里可能有更好的方法。 任何有关我的答复的反馈意见。

我遇到过这个问题,解决方法是:

 if (strpos($_SERVER['REQUEST_URI'], basename(__FILE__)) !== false) ... 

但理想的解决scheme是将文件放置在Web服务器文档根目录之外,如另一个选项所述。

你最好build立一个入口点的应用程序,即所有的文件应该从index.php到达

把它放在index.php中

 define(A,true); 

这个检查应该在每个链接文件中运行(通过require或include)

 defined('A') or die(header('HTTP/1.0 403 Forbidden')); 

最简单的方法是在调用include的文件中设置一些variables,比如

 $including = true; 

然后在包含的文件中,检查variables

 if (!$including) exit("direct access not permitted"); 

什么Joomla! 在根文件中定义一个常量并检查是否在包含文件中定义了常量。

 defined('_JEXEC') or die('Restricted access'); 

要不然

通过将它们放在webroot目录之外,可以将所有文件保留在http请求的范围之外,因为像CodeIgniter这样的大多数框架都是推荐的。

或者甚至通过将.htaccess文件放入包含文件夹并编写规则,您可以防止直接访问。

 debug_backtrace() || die ("Direct access not permitted"); 

除了.htaccess之外,我还看到了各种框架中的一个有用的模式,例如Ruby on Rails。 他们在应用程序根目录下有一个单独的pub /目录,而且这些库目录与pub /的目录位于相同的目录中。 像这样(不理想,但你明白了):

 app/ | +--pub/ | +--lib/ | +--conf/ | +--models/ | +--views/ | +--controllers/ 

您将您的Web服务器设置为使用pub /作为文档根目录。 这为您的脚本提供了更好的保护:当他们可以从文档根目录中加载必要的组件时,不可能从互联网访问组件。 除了安全之外,另一个好处就是一切都在一个地方。

这个设置比在每个包含文件中创build检查要好,因为“访问不允许”消息是攻击者的线索,它比.htaccessconfiguration更好,因为它不是基于白名单:如果你搞砸了文件扩展名它不会在lib /,conf / etc目录中可见。

如果更确切地说,你应该使用这个条件:

 if (array_search(__FILE__, get_included_files()) === 0) { echo 'direct access'; } else { echo 'included'; } 

get_included_files()返回包含所有包含文件的名称的索引数组(如果文件是被执行的,那么它被包含并且它的名字在数组中)。 所以,当文件被直接访问时,其名称是数组中的第一个,数组中的所有其他文件都包含在内。

 <?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>"); } ?> 

把上面的代码放在你包含的php文件的顶部。

例如:

 <?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 ?> 

以下代码在Flatnux CMS( http://flatnux.altervista.org )中使用:

 if ( strpos(strtolower($_SERVER['SCRIPT_NAME']),strtolower(basename(__FILE__))) ) { header("Location: ../../index.php"); die("..."); } 
 if (basename($_SERVER['PHP_SELF']) == basename(__FILE__)) { die('Access denied'); }; 

我的答案在方法上有些不同,但包含了许多这里提供的答案。 我会build议一个多pipe齐下的方法:

  1. .htaccess和Apache的限制肯定
  2. defined('_SOMECONSTANT') or die('Hackers! Be gone!');

然而 defined or die方法有一些失败。 首先,testing和debugging的假设是一个真正的痛苦。 其次,如果你改变主意的话,它会令人恐惧的,令人头脑无聊的重构。 “查找和replace!” 你说。 是的,但是你有多确定它到处都是一样的,嗯? 现在把它与数以千计的文件相乘… oo

然后是.htaccess。 如果您的代码分发到pipe理员不那么认真的站点上,会发生什么? 如果你只依赖.htaccess来保护你的文件,你还需要a)备份,b)一盒纸巾,擦干你的眼泪,c)一个灭火器,把火焰扑灭使用你的代码。

所以我知道这个问题要求“最简单”,但我认为这个要求更多的是“防御性编码”。

我build议的是:

  1. 在你的任何脚本require('ifyoulieyougonnadie.php'); include()和作为defined or die的替代)
  2. ifyoulieyougonnadie.php ,做一些逻辑的东西 – 检查不同的常量,调用脚本,本地主机testing等 – 然后执行你的die(), throw new Exception, 403

    我创build了自己的框架,有两个可能的入口点 – 主index.php(Joomla框架)和ajaxrouter.php(我的框架) – 所以根据入口点,我检查不同的东西。 如果对ifyoulieyougonnadie.php的请求不是来自这两个文件中的一个,我知道正在进行ifyoulieyougonnadie.php

    但是如果我添加一个新的入口点呢? 别担心。 我只是改变ifyoulieyougonnadie.php ,我sorting,再加上没有“查找和replace”。 万岁!

    如果我决定移动我的一些脚本来做一个不具有相同的常量defined()框架呢? …万岁! ^ _ ^

我发现这个策略使得开发更有趣,而且更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(); 
 if ( ! defined('BASEPATH')) exit('No direct script access allowed'); 

将顺利完成工作

做类似的事情:

 <?php if ($_SERVER['SCRIPT_FILENAME'] == '<path to php include file>') { header('HTTP/1.0 403 Forbidden'); exit('Forbidden'); } ?> 

我发现这个PHP的唯一和不变的解决scheme,与http和cli一起工作:

定义一个函数:

 function forbidDirectAccess($file) { $self = getcwd()."/".trim($_SERVER["PHP_SELF"], "/"); (substr_compare($file, $self, -strlen($self)) != 0) or die('Restricted access'); } 

调用您想阻止直接访问的文件中的函数:

 forbidDirectAccess(__FILE__); 

上面给出的这个问题的大部分解决scheme都不能在Cli模式下工作。

您可以使用下面的方法,虽然它有一个缺陷,因为它可能是伪造的,除非您可以添加另一行代码,以确保请求只通过使用Javascript从您的服务器来。 您可以将此代码放置在HTML代码的正文部分,以便在此处显示错误。

 <? if(!isset($_SERVER['HTTP_REQUEST'])) { include ('error_file.php'); } else { ?> 

将您的其他HTML代码放在这里

 <? } ?> 

像这样结束,所以错误的输出将总是显示在正文部分,如果这是你想要的。

我build议不要使用$_SERVER出于安全原因。
你可以使用像$root=true;这样的variables$root=true; 在第一个文件,包括另一个。
并在包含的第二个文件的开头使用isset($root)

你也可以做的是密码保护的目录,并保持所有的PHP脚本在那里,除了index.php文件,因为在包括密码将不需要,因为它将只需要访问http访问。 它会做的也是提供你select访问你的脚本,如果你想要的话,因为你将有密码来访问该目录。 您需要设置目录的.htaccess文件和.htpasswd文件来validation用户。

好吧,你也可以使用上面提供的任何解决scheme,以防你不需要正常访问这些文件,因为你总是可以通过cPanel访问它们。

希望这可以帮助

最简单的方法是将您的包含存储在Web目录之外。 这样的服务器有权访问他们,但没有外部机器。 唯一的缺点是你需要能够访问你的服务器的这一部分。 好处是不需要设置,configuration或附加的代码/服务器压力。

 <?php $url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']; if (false !== strpos($url,'.php')) { die ("Direct access not premitted"); } ?> 

我没有find与.htaccess这么好的build议,因为它可能会阻止您可能要允许用户访问该文件夹中的其他内容,这是我的解决scheme:

 $currentFileInfo = pathinfo(__FILE__); $requestInfo = pathinfo($_SERVER['REQUEST_URI']); if($currentFileInfo['basename'] == $requestInfo['basename']){ // direct access to file } 

前面提到的PHP版本检查解决scheme增加了:

  $max_includes = version_compare(PHP_VERSION, '5', '<') ? 0 : 1; if (count(get_included_files()) <= $max_includes) { exit('Direct access is not allowed.'); } 

你可以使用phpMyAdmin风格:

 /** * block attempts to directly run this script */ if (getcwd() == dirname(__FILE__)) { die('Attack stopped'); } 

我想限制直接访问PHP文件,但也可以通过jQuery $.ajax (XMLHttpRequest)来调用它。 这是为我工作。

 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; } }