阻止直接访问php包含文件

Alt*_*ife 160 php include-guards include

我有一个php文件,我将作为一个包含专门使用.因此,当我通过输入URL而不是包含它来直接访问它时,我想抛出一个错误而不是执行它.

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

if ( $REQUEST_URL == $URL_OF_CURRENT_PAGE ) die ("Direct access not premitted");
Run Code Online (Sandbox Code Playgroud)

是否有捷径可寻?

Unk*_*ech 179

将其添加到您只想包含的页面中

<?php
if(!defined('MyConst')) {
   die('Direct access not permitted');
}
?>
Run Code Online (Sandbox Code Playgroud)

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

<?php
define('MyConst', TRUE);
?>
Run Code Online (Sandbox Code Playgroud)

  • 只需发送404标头并退出 - 错误页面看起来与普通的404页面相同(至少在Apache上). (7认同)
  • 我真的需要学习更快地打字.这与我建议的方式相同,因为它比使用变量检查的方法更安全.由于使用了一些PHP设置,因此可以覆盖变量. (3认同)
  • 这是一些"主流"应用程序处理它的方式.我知道Joomla是这样做的,我认为Wiki,Wordpress和其他人也是如此. (3认同)
  • @ Smile.Hunter:这是关于阻止访问直接查看您的包含/库脚本文件,答案是有效的.如果他们在您的服务器上创建了`somefile.php`并在其中添加了您的定义,那仍然不允许他们直接访问包含文件.它会让他们"包含"你的库文件,但是如果它们足够远,可以在你的服务器上创建文件并知道你的定义/包含脚本,那么你有其他问题可能会否定用你的定义编写自己的文件. (3认同)
  • 拒绝具有相同结果的访问的更短方法是:`defined('MyConst') || die('不允许直接访问');` (2认同)

Chu*_*uck 164

在您可能或可能无法完全控制的Apache服务器上运行的通用"PHP应用程序"最简单的方法是将您的包含放在目录中,并拒绝访问.htaccess文件中的该目录.为了省去Googling的麻烦,如果你正在使用Apache,请将它放在你不想访问的目录中名为".htaccess"的文件中:

Deny from all
Run Code Online (Sandbox Code Playgroud)

如果您实际上完全控制了服务器(这些天甚至对于小应用程序来说比我第一次写这个答案时更常见),最好的方法是将要保护的文件粘贴到Web服务器所服务的目录之外. .因此,如果您的应用程序处于中/srv/YourApp/,请将服务器设置为提供文件/srv/YourApp/app/并将其包含在内/srv/YourApp/includes,因此实际上并不存在可以访问它们的任何URL.

  • 如果您将配置放入虚拟主机配置文件中的目录指令,则可以更好地控制服务器.Apache在启动时只读取一次,每次访问都会读取.htaccess并使服务器变慢 (22认同)
  • 很高兴有一个示例.htaccess文件作为这个答案的一部分. (20认同)
  • @James:而且,并非所有人都认为Stack Overflow应该是一个"plz send teh codez"网站.如果它清楚地回答了这个问题,那么这是一个很好的答案.提供不需要的示例仅鼓励复制和粘贴编码. (9认同)
  • `<Files~"\ .inc $">``Order Allow,Deny``Deny from All`` </ Files> (7认同)
  • 我试过这个,如果你做“拒绝所有人”,它甚至不会在包含中工作,它会是 404。 (2认同)

nul*_*ull 110

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

if(count(get_included_files()) ==1) exit("Direct access not permitted.");
Run Code Online (Sandbox Code Playgroud)

被访问的文件始终是包含文件,因此== 1.  

  • 这实际上是一个想法,检查包含文件计数.我想知道哪个更好:使用定义,还是使用这种方法?这看起来更加自足. (11认同)
  • 这仅适用于PHP5及更高版本.在PHP5之前,你想再次比较0而不是1. (3认同)

Era*_*rin 32

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

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

  • 在某些主机(包括我当前的主机)上,您可以将域指向您希望的任何文件夹. (3认同)
  • 如果您能够这样做,这是一个很好的解决方案.我最近才开始使用共享的webhosts,并发现许多烦恼之一,一切都必须在docroot内. (2认同)
  • 在我工作过的每个托管服务提供商中,我总是可以访问(完全)文档根目录上的一个级别. (2认同)

Kev*_*ney 26

Chuck解决方案的另一种选择(或补充)是通过在.htaccess文件中放置类似的东西来拒绝访问与特定模式匹配的文件

<FilesMatch "\.(inc)$">
    Order deny,allow
    Deny from all
</FilesMatch>
Run Code Online (Sandbox Code Playgroud)


RiA*_*RiA 26

1:检查包含文件的数量

if( count(get_included_files()) == ((version_compare(PHP_VERSION, '5.0.0', '>='))?1:0) )
{
    exit('Restricted Access');
}
Run Code Online (Sandbox Code Playgroud)

逻辑:如果不满足最小包含计数,PHP将退出.请注意,在PHP5之前,基页不被视为包含.


2:定义和验证全局常量

// 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');
Run Code Online (Sandbox Code Playgroud)

逻辑:如果未定义常量,则执行不会从基页开始,PHP将停止执行.


3:远程地址授权

// 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');
Run Code Online (Sandbox Code Playgroud)

除非提供内部请求的会话令牌,否则此方法的缺点是隔离执行.在单个服务器配置的情况下通过环回地址进行验证,或者在多服务器或负载平衡的服务器基础结构的地址白名单中进行验证.


4:令牌授权

与前面的方法类似,可以使用GET或POST将授权令牌传递给包含文件:

if($key!="serv97602"){header("Location: ".$dart);exit();}
Run Code Online (Sandbox Code Playgroud)

一种非常混乱的方法,但也许是最安全和多功能的同时,以正确的方式使用.


5:Webserver特定配置

大多数服务器允许您为单个文件或目录分配权限.您可以将所有包含放在此类受限目录中,并将服务器配置为拒绝它们.

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

请注意,我不建议使用特定于服务器的配置,因为它们不适合跨不同Web服务器的可移植性.在拒绝算法很复杂或者拒绝目录列表相当大的情况下,它可能只会使重新配置会话变得非常可怕.最后,最好在代码中处理这个问题.


6:放置包含在站点根目录外的安全目录中

由于服务器环境中的访问限制,最不受欢迎,但如果您有权访问文件系统,则这是一种相当强大的方法.

//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");
Run Code Online (Sandbox Code Playgroud)

逻辑:

  • 用户无法请求文件htdocs夹外的任何文件,因为链接不在网站的地址系统范围内.
  • php服务器本地访问文件系统,因此可以访问计算机上的文件,就像具有所需权限的普通程序一样.
  • 通过将包含文件放在此目录中,可以确保php服务器可以访问它们,同时拒绝用户进行热链接.
  • 即使Web服务器的文件系统访问配置未正确完成,此方法也会阻止这些文件意外泄露.

请原谅我的非正统编码约定.任何反馈都表示赞赏.

  • 我喜欢2号 (2认同)

jmu*_*llo 15

实际上我的建议是做所有这些最佳实践.

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

这样,如果文件以某种方式错位(错误的ftp操作),它们仍然受到保护.


小智 8

我曾经遇到过这个问题,解决了:

if (strpos($_SERVER['REQUEST_URI'], basename(__FILE__)) !== false) ...
Run Code Online (Sandbox Code Playgroud)

但理想的解决方案是将文件放在Web服务器文档根目录之外,如另一个anwser中所述.


Uni*_*rgy 5

debug_backtrace() || die ("Direct access not permitted");
Run Code Online (Sandbox Code Playgroud)


小智 5

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

将它放在index.php中

define(A,true);
Run Code Online (Sandbox Code Playgroud)

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

defined('A') or die(header('HTTP/1.0 403 Forbidden'));
Run Code Online (Sandbox Code Playgroud)


小智 5

我的答案在方法上有些不同,但包含了此处提供的许多答案。我建议采取多管齐下的方法:

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

然而,这种defined or die方法有许多缺点。首先,测试和调试的假设确实很痛苦。其次,如果你改变主意,它会涉及到可怕的、令人麻木的、无聊的重构。“查找和替换!” 你说。是的,但是你怎么确定到处都写得一模一样,嗯?现在乘以数千个文件... oO

然后是.htaccess。如果您的代码分发到管理员不那么谨慎的网站上,会发生什么?如果您仅依靠 .htaccess 来保护您的文件,您还需要 a) 备份,b) 一盒纸巾来擦干眼泪,c) 一个灭火器来扑灭来自人们的所有仇恨邮件中的火焰使用你的代码。

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

我的建议是:

  1. 在您的任何脚本之前require('ifyoulieyougonnadie.php');不是 include()并且作为替换defined or die
  2. 在 中ifyoulieyougonnadie.php,做一些逻辑工作 - 检查不同的常量、调用脚本、本地主机测试等 - 然后实现你的die(), throw new Exception, 403等。

    我正在使用两个可能的入口点创建自己的框架 - 主index.php(Joomla框架)和ajaxrouter.php(我的框架) - 因此根据入口点,我检查不同的东西。如果请求ifyoulieyougonnadie.php不是来自这两个文件之一,我就知道有人在搞恶作剧!

    但是如果我添加一个新的入口点怎么办?不用担心。我只是进行了更改ifyoulieyougonnadie.php,然后进行了排序,而且没有“查找和替换”。万岁!

    如果我决定将一些脚本移至不具有相同常量的不同框架,该怎么办defined()?...万岁!^_^

我发现这个策略让开发变得更有趣,而且更少:

/**
 * 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();
Run Code Online (Sandbox Code Playgroud)


kra*_*vov 5

我想直接限制对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;
    }
}
Run Code Online (Sandbox Code Playgroud)