我有一个php文件,我将专门将其用作包含文件。因此,我想抛出一个错误而不是在直接通过输入URL而不是将其包含而直接访问它时执行该错误。
基本上我需要在php文件中进行如下检查:
if ( $REQUEST_URL == $URL_OF_CURRENT_PAGE ) die ("Direct access not premitted");
是否有捷径可寻?
我有一个php文件,我将专门将其用作包含文件。因此,我想抛出一个错误而不是在直接通过输入URL而不是将其包含而直接访问它时执行该错误。
基本上我需要在php文件中进行如下检查:
if ( $REQUEST_URL == $URL_OF_CURRENT_PAGE ) die ("Direct access not premitted");
是否有捷径可寻?
Answers:
通用的“您可能会或可能不会完全控制的在Apache服务器上运行的PHP应用程序”情况的最简单方法是将includes放在目录中,并拒绝访问.htaccess文件中的该目录。为了避免人们使用谷歌搜索的麻烦,如果您使用的是Apache,请将其放入您不希望访问的目录中的“ .htaccess”文件中:
Deny from all
如果您实际上完全控制了服务器(如今,即使是很小的应用程序,如今也比我初次写此答案时更常见),最好的方法是将要保护的文件粘贴到Web服务器所服务的目录之外。因此,如果您的应用程序位于中/srv/YourApp/
,请将服务器设置为从中提供文件/srv/YourApp/app/
,并将包含内容放入中/srv/YourApp/includes
,因此实际上没有任何URL可以访问它们。
<Files ~ "\.inc$">
Order Allow,Deny
Deny from All
</Files>
将此添加到您只想包含的页面中
<?php
if(!defined('MyConst')) {
die('Direct access not permitted');
}
?>
然后在包含它的页面上添加
<?php
define('MyConst', TRUE);
?>
somefile.php
在您的服务器上创建并在其中添加了您的定义,那仍然不允许他们直接访问包含文件。它将使它们“包含”您的库文件,但是如果它们足够远,无法在服务器上创建文件并知道您的定义/包含脚本,那么您还有其他问题,很可能首先会否定使用自己的定义编写自己的文件。
我有一个文件,在包含文件时和直接访问文件时(主要是print()
vs return()
),我需要采取不同的操作。这是一些修改后的代码:
if(count(get_included_files()) ==1) exit("Direct access not permitted.");
被访问的文件始终是一个包含的文件,因此== 1。
防止直接访问文件的最佳方法是将它们放置在Web服务器文档根目录之外(通常位于上一级)。您仍然可以包括它们,但是不可能有人通过http请求访问它们。
我通常一路走来,将所有PHP文件放置在文档根目录之外的引导文件之外 - 引导目录中唯一的index.php,它开始路由整个网站/应用程序。
if( count(get_included_files()) == ((version_compare(PHP_VERSION, '5.0.0', '>='))?1:0) )
{
exit('Restricted Access');
}
逻辑:如果不满足最小包含数,PHP将退出。请注意,在PHP5之前,基本页面不被视为包含。
// 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');
逻辑:如果未定义常量,则执行不是从基础页开始的,PHP将停止执行。
请注意,为了在升级和将来的更改之间具有可移植性,将这种身份验证方法模块化可以显着减少编码开销,因为不需要将更改硬编码到每个文件。
// 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
日志记录和分析目的,以及生成适当的响应。
应归功于信誉:可移植性的绝妙想法来自此答案。
// 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将授权令牌传递到包含文件:
if($key!="serv97602"){header("Location: ".$dart);exit();}
如果使用正确的方法,这是一种非常混乱的方法,但同时也可能是最安全和最通用的。
大多数服务器允许您为单个文件或目录分配权限。您可以将所有包含项放在这样的受限目录中,并配置服务器以拒绝它们。
例如,在APACHE中,配置存储在.htaccess
文件中。教程在这里。
但是请注意,我不建议使用服务器特定的配置,因为它们不利于跨不同Web服务器的可移植性。在诸如内容管理系统之类的拒绝算法很复杂或被拒绝目录的列表很大的情况下,它可能只会使重新配置会话变得非常麻烦。最后,最好用代码来处理。
由于服务器环境中的访问限制,因此最不推荐使用,但如果可以访问文件系统,则是一种功能非常强大的方法。
//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文件的访问,但也可以通过调用它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;
}
}
最简单的方法是在调用包含的文件中设置一些变量,例如
$including = true;
然后在包含的文件中,检查变量
if (!$including) exit("direct access not permitted");
除了.htaccess方式以外,我还在各种框架中看到了有用的模式,例如在Rails上的ruby中。它们在应用程序根目录中有一个单独的pub /目录,而库目录位于与 pub / 处于同一级别的目录中。像这样的东西(不理想,但您知道了):
app/
|
+--pub/
|
+--lib/
|
+--conf/
|
+--models/
|
+--views/
|
+--controllers/
您将Web服务器设置为使用pub /作为文档根目录。这可以为您的脚本提供更好的保护:尽管它们可以从文档根目录伸出以加载必要的组件,但无法从Internet访问这些组件。除安全性外的另一个好处是,一切都在一个地方。
此设置比只在每个包含的文件中创建检查要好,因为“不允许访问”消息是攻击者的线索,它比.htaccess配置要好,因为它不是基于白名单的:如果您破坏了文件扩展名它在lib /,conf / etc等目录中不可见。
什么Joomla!要做的是在根文件中定义一个常量,并检查是否在包含的文件中定义了该常量。
defined('_JEXEC') or die('Restricted access');
要不然
可以将大多数文件(如CodeIgniter所建议的那样)放置在webroot目录之外,从而将所有文件保留在http请求的范围之外。
甚至将.htaccess文件放在include文件夹中并编写规则,就可以防止直接访问。
我的答案在方法上有所不同,但包括此处提供的许多答案。我建议采用多管齐下的方法:
defined('_SOMECONSTANT') or die('Hackers! Be gone!');
但是,这种defined or die
方法有很多缺点。首先,在进行测试和调试的假设中确实是一个痛苦。其次,如果您改变主意,它将涉及令人恐惧,令人麻木的无聊重构。“查找和替换!” 你说。是的,但是您如何确定它在任何地方都完全相同,嗯?现在,将其与成千上万个文件相乘...
然后是.htaccess。如果将您的代码分发到管理员不是很谨慎的站点上会怎样?如果仅依靠.htaccess来保护文件安全,则还需要a)备份,b)一盒纸巾擦干眼泪,c)灭火器以扑灭人们发来的所有仇恨邮件使用您的代码。
所以我知道这个问题要求“最简单”,但是我认为这要求的是更多“防御性编码”。
我的建议是:
require('ifyoulieyougonnadie.php');
(不是 include()
和替代defined or die
)在中ifyoulieyougonnadie.php
,执行一些逻辑操作-检查不同的常量,调用脚本,localhost测试等-然后实现您的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();
如果更精确地讲,则应使用以下条件:
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("...");
}
我发现了这种仅适用于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模式下均不起作用。
已经多次提到将包含文件存储在Web可访问目录之外,并且在可能的情况下肯定是个不错的策略。但是,我还没有提到另一种选择:确保包含文件中不包含任何可运行的代码。如果包含文件仅定义函数和类,并且没有其他代码,则直接访问它们时,它们只会产生空白页。
绝对允许从浏览器直接访问此文件:它不会做任何事情。它定义了一些函数,但是没有一个被调用,因此它们都不运行。
<?php
function a() {
// function body
}
function b() {
// function body
}
这同样适用于仅包含PHP类,而不包含其他任何类的文件。
最好将文件尽可能保留在Web目录之外。
system
,因为这将与用于代码的路径冲突。我觉得这很烦人。尽管您可以使用以下方法,但是它确实存在缺陷,因为它可以被伪造,除非您可以添加另一行代码以确保请求仅通过使用Javascript来自服务器来进行。您可以将此代码放在HTML代码的“正文”部分中,因此该错误在那里显示。
<?
if(!isset($_SERVER['HTTP_REQUEST'])) { include ('error_file.php'); }
else { ?>
将其他HTML代码放在此处
<? } ?>
像这样结束它,因此错误的输出将始终显示在主体部分中(如果您希望这样做的话)。
最简单的方法是将包含内容存储在Web目录之外。这样服务器可以访问它们,但没有外部计算机。唯一的缺点是您需要能够访问服务器的这一部分。好处是不需要设置,配置或额外的代码/服务器压力。
前面提到的解决方案添加了PHP版本检查:
$max_includes = version_compare(PHP_VERSION, '5', '<') ? 0 : 1;
if (count(get_included_files()) <= $max_includes)
{
exit('Direct access is not allowed.');
}