题
我有一个 php 文件,我将专门将其用作包含文件。因此,当通过输入 URL 直接访问而不是包含在内时,我想抛出一个错误而不是执行它。
基本上我需要在 php 文件中进行如下检查:
if ( $REQUEST_URL == $URL_OF_CURRENT_PAGE ) die ("Direct access not premitted");
是否有捷径可寻?
解决方案
在Apache服务器上运行的通用<!>“PHP应用程序的最简单方法,您可能会或可能不会完全控制<!>”;情况是将您的包含在目录中并拒绝访问.htaccess文件中的该目录。为了省去Googling的麻烦,如果你使用的是Apache,请把它放在一个名为<!> quot; .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. <!> nbsp;
阻止直接访问文件的最佳方法是将它们放在Web服务器文档根目录之外(通常在上面一级)。您仍然可以包含它们,但不可能有人通过http请求访问它们。
我通常会一路走下去,并将所有PHP文件放在文档根目录之外,而不是 bootstrap文件 - 文档根目录中唯一的index.php,它开始路由整个网站/应用程序。
Chuck解决方案的另一种选择(或补充)是通过在.htaccess文件中添加类似的内容来拒绝访问与特定模式匹配的文件
<FilesMatch "\.(inc)$">
Order deny,allow
Deny from all
</FilesMatch>
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');
逻辑: 如果未定义常量,则不会从基页开始执行,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');
此方法的缺点是隔离执行,除非内部请求提供会话令牌。在单服务器配置的情况下通过环回地址进行验证,或者在多服务器或负载平衡服务器基础设施的情况下通过地址白名单进行验证。
4:令牌授权
与前一种方法类似,可以使用 GET 或 POST 将授权令牌传递到包含文件:
if($key!="serv97602"){header("Location: ".$dart);exit();}
这是一种非常混乱的方法,但如果以正确的方式使用,它也可能是最安全和最通用的方法。
5:Web服务器特定配置
大多数服务器允许您为单个文件或目录分配权限。您可以将所有包含内容放入此类受限目录中,并将服务器配置为拒绝它们。
例如在 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");
逻辑:
- 用户不能请求任何超出范围的文件
htdocs
文件夹,因为链接将超出网站地址系统的范围。 - php 服务器本身访问文件系统,因此可以像具有所需权限的普通程序一样访问计算机上的文件。
- 通过将包含文件放入此目录中,您可以确保 php 服务器可以访问它们,同时拒绝用户进行热链接。
- 即使网络服务器的文件系统访问配置没有正确完成,此方法也可以防止这些文件意外公开。
请原谅我的非正统编码约定。如有任何反馈,我们将不胜感激。
实际上我的建议是采用所有这些最佳实践。
- 将文档放在 webroot 之外或 Web 服务器拒绝访问的目录中 和
- 在隐藏文档检查的可见文档中使用定义:
if (!defined(INCL_FILE_FOO)) {
header('HTTP/1.0 403 Forbidden');
exit;
}
这样,如果文件因某种原因丢失(错误的 ftp 操作),它们仍然受到保护。
我曾经遇到过这个问题,解决了:
if (strpos($_SERVER['REQUEST_URI'], basename(__FILE__)) !== false) ...
但理想的解决方案是将文件放在Web服务器文档根目录之外,如另一个anwser中所述。
你最好用一个入口点构建应用程序,即所有文件都应该从index.php
到达将其放在index.php
中define(A,true);
此检查应在每个链接文件中运行(通过require或include)
defined('A') or die(header('HTTP/1.0 403 Forbidden'));
最简单的方法是在调用include的文件中设置一些变量,例如
$including = true;
然后在包含的文件中,检查变量
if (!$including) exit("direct access not permitted");
Joomla!确实是在根文件中定义一个常量并检查是否在包含的文件中定义了它。
defined('_JEXEC') or die('Restricted access');
或者
通过将它们放在webroot目录之外,可以将所有文件保留在http请求范围之外,就像大多数框架一样,如CodeIgniter建议的那样。或者甚至通过在include文件夹中放置.htaccess文件并编写规则,可以防止直接访问。
debug_backtrace() || die ("Direct access not permitted");
我想直接限制对 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;
}
}
除了.htaccess方式之外,我在各种框架中看到了一个有用的模式,例如在rails上的ruby中。它们在应用程序根目录中有一个单独的pub /目录,库目录位于相同级别的目录中,作为pub /。这样的事情(不理想,但你明白了):
app/
|
+--pub/
|
+--lib/
|
+--conf/
|
+--models/
|
+--views/
|
+--controllers/
您将Web服务器设置为使用pub /作为文档根目录。这为您的脚本提供了更好的保护:虽然他们可以从文档根目录进行访问以加载必要的组件,但是无法从Internet访问组件。除安全性之外的另一个好处是一切都在一个地方。
此设置优于仅在每个包含的文件中创建检查,因为<!>“;不允许访问<!>”;消息是攻击者的线索,它比.htaccess配置更好,因为它不是基于白名单的:如果搞砸了文件扩展名,它将无法在lib /,conf / etc.目录中看到。
如果更确切地说,你应该使用这个条件:
if (array_search(__FILE__, get_included_files()) === 0) {
echo 'direct access';
}
else {
echo 'included';
}
get_included_files()返回包含所有名称的索引数组包含的文件(如果文件是beign执行,那么它被包含在内,其名称在数组中)。 因此,当直接访问文件时,它的名称是数组中的第一个,数组中的所有其他文件都包含在内。
<?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模式。
if (basename($_SERVER['PHP_SELF']) == basename(__FILE__)) { die('Access denied'); };
我的答案在方法上有些不同,但包含了此处提供的许多答案。我建议采取多管齐下的方法:
- .htaccess 和 Apache 的限制是肯定的
defined('_SOMECONSTANT') or die('Hackers! Be gone!');
然而 这 defined or die
这种方法有许多缺点。首先,测试和调试的假设确实很痛苦。其次,如果你改变主意,它会涉及到可怕的、令人麻木的、无聊的重构。“找到并替换!”你说。是的,但是你怎么确定到处都写得一模一样,嗯?现在乘以数千个文件......o.O
然后是.htaccess。如果您的代码分发到管理员不那么谨慎的网站上,会发生什么?如果您仅依靠 .htaccess 来保护您的文件,您还需要 a) 备份,b) 一盒纸巾来擦干眼泪,c) 一个灭火器来扑灭来自人们的所有仇恨邮件中的火焰使用你的代码。
所以我知道这个问题要求“最简单”,但我认为这需要更多的“防御性编码”。
我的建议是:
- 在任何脚本之前
require('ifyoulieyougonnadie.php');
(不是include()
并作为替代品defined or die
) 在
ifyoulieyougonnadie.php
, ,做一些逻辑工作 - 检查不同的常量,调用脚本,本地主机测试等 - 然后实现你的die(), throw new Exception, 403
, , ETC。我正在使用两个可能的入口点创建自己的框架 - 主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();
做类似的事情:
<?php
if ($_SERVER['SCRIPT_FILENAME'] == '<path to php include file>') {
header('HTTP/1.0 403 Forbidden');
exit('Forbidden');
}
?>
你可以使用下面的方法,虽然它有一个缺陷,因为它可以伪造,除非你可以添加另一行代码,以确保请求只来自你的服务器使用Javascript。 您可以将此代码放在HTML代码的“正文”部分中,以便显示错误。
<?
if(!isset($_SERVER['HTTP_REQUEST'])) { include ('error_file.php'); }
else { ?>
将您的其他HTML代码放在此处
<? } ?>
这样结束它,所以错误的输出将始终显示在body部分中,如果这是你想要的那样。
我建议不要出于安全原因使用$_SERVER
。
您可以在包含另一个文件的第一个文件中使用类似$root=true;
的变量
并在包含的第二个文件的开头使用isset($root)
。
您还可以做的是密码保护目录并保留所有PHP脚本,除了index.php文件之外,因为在包含密码时不需要,因为它只需要http访问。如果您需要它,它将为您提供访问脚本的选项,因为您将拥有访问该目录的密码。您需要为目录设置.htaccess文件,并使用.htpasswd文件对用户进行身份验证。
好吧,如果您觉得不需要正常访问这些文件,也可以使用上面提供的任何解决方案,因为您始终可以通过cPanel等访问它们。
希望这有帮助
最简单的方法是将您的包含存储在Web目录之外。这样服务器可以访问它们,但没有外部机器。唯一的缺点是您需要能够访问服务器的这一部分。好处是它不需要设置,配置或额外的代码/服务器压力。
<?php
$url = 'http://' . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'];
if (false !== strpos($url,'.php')) {
die ("Direct access not premitted");
}
?>
我没有找到.htaccess的建议那么好,因为它可能会阻止 您可能希望允许用户访问的该文件夹中的其他内容, 这是我的解决方案:
$currentFileInfo = pathinfo(__FILE__);
$requestInfo = pathinfo($_SERVER['REQUEST_URI']);
if($currentFileInfo['basename'] == $requestInfo['basename']){
// direct access to file
}
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
将顺利完成工作
您可以使用phpMyAdmin Style:
/**
* block attempts to directly run this script
*/
if (getcwd() == dirname(__FILE__)) {
die('Attack stopped');
}
这是google在他们的php示例中使用的见这里
if (php_sapi_name() != 'cli') {
throw new \Exception('This application must be run on the command line.');
}