代码之家  ›  专栏  ›  技术社区  ›  Alterlife

阻止直接访问php包含文件

  •  148
  • Alterlife  · 技术社区  · 16 年前

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

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

    有没有一个简单的方法可以做到这一点?

    33 回复  |  直到 11 年前
        1
  •  206
  •   Amal Murali    11 年前

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

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

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

    <?php
    define('MyConst', TRUE);
    ?>
    
        2
  •  182
  •   Chuck    10 年前

    对于一般的“在Apache服务器上运行的PHP应用程序,您可以完全控制,也可以不完全控制”情况,最简单的方法是将您的include放在一个目录中,并拒绝对.htaccess文件中该目录的访问。为了避免人们使用谷歌搜索的麻烦,如果您使用的是Apache,请将其放入一个名为“.htaccess”的文件中,该文件位于您不希望访问的目录中:

    Deny from all
    

    /srv/YourApp/ ,将服务器设置为从中提供文件 /srv/YourApp/app/ /srv/YourApp/includes

        3
  •  118
  •   OCDev    9 年前

    我有一个文件,当它被包含时,我需要采取不同的行动,而当它被直接访问时(主要是 print() return() )下面是一些修改后的代码:

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

    正在访问的文件始终是包含的文件,因此==1。

        4
  •  36
  •   Eran Galperin    16 年前

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

    我通常会一直这样做,并将所有PHP文件放在文档根目录之外,而不是 bootstrap file -文档根目录中的一个单独的index.php,开始路由整个网站/应用程序。

        5
  •  36
  •   Community CDub    4 年前

    1:检查包含文件的计数

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

    逻辑: 如果未满足最小包含计数,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');
    

    逻辑:

    为了跨升级和未来更改的可移植性,将此身份验证方法模块化将显著减少编码开销,因为更改不需要硬编码到每个文件。

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

    这样就可以将其他代码添加到 checkdefined.php 用于记录和分析目的,以及生成适当的响应。

    可移植性的绝妙想法来自于 this answer .


    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');
    

    此方法的缺点是独立执行,除非内部请求中提供了会话令牌。如果是单服务器配置,则通过环回地址进行验证;如果是多服务器或负载平衡服务器基础结构,则通过地址白名单进行验证。


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

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

    这是一种非常混乱的方法,但如果使用正确的方式,可能也是最安全和通用的方法。


    5:特定于Web服务器的配置

    例如,在APACHE中,配置存储在 .htaccess 文件辅导的 here .

    笔记 但是,我不推荐特定于服务器的配置,因为它们不利于跨不同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");
    

    逻辑:

    • 用户无法请求服务器之外的任何文件 htdocs 文件夹作为链接将超出网站地址系统的范围。
    • php服务器以本机方式访问文件系统,因此可以像具有所需权限的普通程序一样访问计算机上的文件。
    • 通过将include文件放在这个目录中,您可以确保php服务器能够访问它们,同时拒绝用户进行热链接。
    • 即使Web服务器的文件系统访问配置没有正确完成,此方法也可以防止这些文件意外公开。

    请原谅我的非正统编码惯例。任何反馈都将不胜感激。

        6
  •  30
  •   NullUserException Mark Roddy    12 年前

    <FilesMatch "\.(inc)$">
        Order deny,allow
        Deny from all
    </FilesMatch>
    
        7
  •  14
  •   jmucchiello    14 年前

    • 将文档放在webroot之外或Web服务器拒绝访问的目录中 和
          if (!defined(INCL_FILE_FOO)) {
              header('HTTP/1.0 403 Forbidden');
              exit;
          }
    

    这样,如果文件不知何故放错了位置(错误的ftp操作),它们仍然受到保护。

        8
  •  8
  •   mati    15 年前

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

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

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

        9
  •  8
  •   Regolith Luciens    7 年前

    我想限制对网络的访问 直接存档,也可以通过 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;
        }
    }
    
        10
  •  7
  •   user2221806    12 年前

    将其放在index.php中

    define(A,true);
    

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

    defined('A') or die(header('HTTP/1.0 403 Forbidden'));
    
        11
  •  4
  •   Kyle Cronin    16 年前

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

    $including = true;
    

    if (!$including) exit("direct access not permitted");
    
        12
  •  4
  •   Unirgy    11 年前
    debug_backtrace() || die ("Direct access not permitted");
    
        13
  •  4
  •   Just Plain High    11 年前

    我的答案在方法上有些不同,但包括这里提供的许多答案。我建议采取多管齐下的办法:

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

    这个 defined or die

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

    我的建议是:

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

      我正在用两个可能的入口点创建自己的框架——main index.php(Joomla framework)和ajaxrouter.php(我的框架)——因此根据入口点,我检查不同的内容。如果请求 如果youlieyougonnadie.php 不是来自这两个文件中的任何一个,我知道有人在搞恶作剧!

      如果youlieyougonnadie.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();
    
        14
  •  3
  •   bandi    16 年前

    同级 作为pub/。类似这样的情况(不理想,但你知道了):

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

    您将web服务器设置为使用pub/as文档根目录。这为您的脚本提供了更好的保护:虽然它们可以从文档根目录中访问以加载必要的组件,但不可能从internet访问这些组件。除了安全之外的另一个好处是,一切都在一个地方。

    此设置优于仅在每个包含的文件中创建检查,因为“不允许访问”消息是攻击者的线索,并且优于.htaccess配置,因为它不是基于白名单的:如果您弄错了文件扩展名,它将在lib/、conf/等目录中不可见。

        15
  •  3
  •   Antony chakradhar kasturi    11 年前

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

    否则

    正如大多数框架(如CodeIgniter)所建议的那样,可以将所有文件放在webroot目录之外,从而使它们不在http请求的范围内。

        16
  •  2
  •   Oleg Lokshyn    10 年前

    更准确地说,您应该使用以下条件:

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

    get_included_files() 返回包含所有包含文件的名称的索引数组(如果文件已被执行,则该文件已被包含,且其名称位于数组中)。

        17
  •  1
  •   Blogging Tips    15 年前
    <?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
    ?>
    
        18
  •  1
  •   JohnRDOrazio    14 年前

    以下代码用于Flatnux CMS( http://flatnux.altervista.org

    if ( strpos(strtolower($_SERVER['SCRIPT_NAME']),strtolower(basename(__FILE__))) )
    {
        header("Location: ../../index.php");
        die("...");
    }
    
        19
  •  1
  •   Ka.    14 年前

    我发现这个仅适用于php且不变的解决方案同时适用于http和cli:

    定义一个函数:

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

    forbidDirectAccess(__FILE__);
    

    上述针对此问题的大多数解决方案在Cli模式下不起作用。

        20
  •  1
  •   andy    11 年前
    if (basename($_SERVER['PHP_SELF']) == basename(__FILE__)) { die('Access denied'); };
    
        21
  •  1
  •   Matt Bettiol    11 年前
    <?php       
    $url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
      if (false !== strpos($url,'.php')) {
          die ("Direct access not premitted");
      }
    ?>
    
        22
  •  1
  •   TRiG    6 年前

    将include文件存储在web可访问目录之外已经提到过几次,如果可能的话,这无疑是一个好策略。但是,我还没有看到提到的另一个选项是:确保您的 不包含任何可运行的代码

    我什么都不会做 . 它定义了一些函数,但是没有一个被调用,所以没有一个运行。

    <?php
    
    function a() {
        // function body
    }
    
    function b() {
        // function body
    }
    

    这同样适用于只包含PHP类而不包含其他类的文件。


    尽可能将文件保存在web目录之外仍然是一个好主意。

    • 您可能会意外地停用PHP,在这种情况下,您的服务器可能会将PHP文件的内容发送到浏览器,而不是运行PHP并发送结果。这可能导致您的代码(包括数据库密码、API密钥等)泄漏。
    • web目录中的文件位于您可能希望用于应用程序的URL上。我使用的CMS不能有一个名为 system
        23
  •  0
  •   kmkaplan    16 年前

    做一些类似于:

    <?php
    if ($_SERVER['SCRIPT_FILENAME'] == '<path to php include file>') {
        header('HTTP/1.0 403 Forbidden');
        exit('Forbidden');
    }
    ?>
    
        24
  •  0
  •   Charming Prince    13 年前

    您可以使用下面的方法,但它确实存在缺陷,因为它可能是伪造的,除非您可以添加另一行代码,以确保请求仅来自您的服务器,或者使用Javascript。 您可以将此代码放在HTML代码的主体部分,因此错误显示在那里。

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

    <? } ?>
    

    这样结束它,这样错误的输出将始终显示在body部分中,如果您希望这样做的话。

        25
  •  0
  •   M Rostami    13 年前

    $_SERVER 出于安全原因。
    可以使用如下变量 $root=true;
    isset($root) 在要包含的第二个文件的开头。

        26
  •  0
  •   RohitG    12 年前

    您还可以对目录进行密码保护,并将所有php脚本保存在目录中,当然,index.php文件除外,因为在使用include时,不需要密码,因为只有http访问才需要密码。它将为您提供访问脚本的选项,以防您需要它,因为您将拥有访问该目录的密码。您需要为目录设置.htaccess文件和.htpasswd文件来验证用户。

    如果您觉得不需要正常访问这些文件,您也可以使用上面提供的任何解决方案,因为您始终可以通过cPanel等访问它们。

        27
  •  0
  •   user1391838 user1391838    11 年前

    最简单的方法是将您的包含存储在web目录之外。这样,服务器就可以访问它们,但没有外部机器。唯一的缺点是您需要能够访问服务器的这一部分。好处是它不需要设置、配置或额外的代码/服务器压力。

        28
  •  0
  •   talsibony    9 年前

    我没有发现.htaccess的建议很好,因为它可能会阻塞 该文件夹中您可能希望允许用户访问的其他内容,

    $currentFileInfo = pathinfo(__FILE__);
    $requestInfo = pathinfo($_SERVER['REQUEST_URI']);
    if($currentFileInfo['basename'] == $requestInfo['basename']){
        // direct access to file
    }
    
        29
  •  0
  •   Milo Wanrooij    9 年前

    前面提到的添加了PHP版本检查的解决方案:

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

    您可以使用phpMyAdmin样式:

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