防止直接访问 php 包含文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/409496/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 22:39:12  来源:igfitidea点击:

Prevent direct access to a php include file

phpincludeinclude-guards

提问by Alterlife

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.

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

Basically I need to do a check as follows in the php file:

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

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

Is there an easy way to do this?

是否有捷径可寻?

回答by UnkwnTech

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

回答by Chuck

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:

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

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.

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

回答by null

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:

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

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

The file being accessed is always an included file, hence the == 1.  

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

回答by Eran Galperin

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.

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

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.

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

回答by RiA

1: Checking the count of included files

1:检查包含文件的数量

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.

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



2: Defining and verifying a global constant

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

Logic:If the constant isn't defined, then the execution didn't start from the base page, and PHP would stop executing.

逻辑:如果没有定义常量,那么执行不是从基页开始,PHP 将停止执行。

Notethat 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 tocheckdefined.phpfor logging and analytical purposes, as well as for generating appropriate responses.

通过这种方式,可以添加额外的代码checkdefined.php用于日志记录和分析目的,以及生成适当的响应。

Credit where credit is due:The brilliant idea of portability came from this answer.

信用应得的地方:可移植性的绝妙想法来自这个答案



3: Remote address authorisation

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

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

4:代币授权

Similar to the previous method, one can use GET or POST to pass an authorization token to the include file:

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

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

5:Webserver特定配置

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 .htaccessfile. Tutorial here.

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

Notehowever 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.

但是请注意,我不推荐特定于服务器的配置,因为它们不利于跨不同 Web 服务器的可移植性。在拒绝算法复杂或被拒绝目录列表相当大的内容管理系统等情况下,它可能只会使重新配置会话变得相当可怕。最后最好在代码中处理这个问题。



6: Placing includes in a secure directory OUTSIDE the site root

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

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 htdocsfolder 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.
  • 用户不能请求文件htdocs夹外的任何文件,因为链接将超出网站地址系统的范围。
  • php 服务器本机访问文件系统,因此可以像具有所需权限的普通程序一样访问计算机上的文件。
  • 通过将包含文件放在此目录中,您可以确保 php 服务器可以访问它们,同时拒绝用户盗链。
  • 即使网络服务器的文件系统访问配置没有正确完成,这种方法也可以防止这些文件意外公开。


Please excuse my unorthodox coding conventions. Any feedback is appreciated.

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

回答by Kevin Loney

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

Chuck 解决方案的替代(或补充)是通过在 .htaccess 文件中放置类似的内容来拒绝访问匹配特定模式的文件

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

回答by jmucchiello

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:
  • 将文档放在 webroot 之外或被网络服务器拒绝访问的目录中,并且
  • 在隐藏文档检查的可见文档中使用定义:
      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.

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

回答by mati

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.

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

回答by user2221806

You'd better build application with one entrance point, i.e. all files should be reached from index.php

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

Place this in index.php

把它放在 index.php 中

define(A,true);

This check should run in each linked file (via require or include)

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

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

回答by krasenslavov

I wanted to restrict access to the PHPfile directly, but also be able to call it via jQuery $.ajax (XMLHttpRequest). Here is what worked for me.

我想直接限制对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;
    }
}