[英]Deny directory and file access with both htaccess and PHP
我目前正在为一个游戏团队开发一个Web项目,并且正在尝试测试自己并扩展我的常识和工具箱。 我正在使用的功能之一要求我“清除”所请求文件的URL。 我已经安装了该系统,并且运行良好。 现在,为了使我的网站“完美无瑕”地工作,我需要通过htaccess拒绝访问某些文件夹以及其中的所有文件。 但是有一个小问题……它需要在用户没有意识到的情况下进行操作。
我的文件结构,首选访问方法,路径和状态如下:
rogue {allow} {direct} {%domain%/dashboard/} {200}
css {deny} {direct} {%domain%/css/} {403}
js {deny} {direct} {%domain%/js/} {403}
fonts {deny} {direct} {%domain%/fonts/} {403}
files {deny} {direct} {%domain%/files/} {403}
image {deny} {direct} {%domain%/image/} {403}
includes {deny} {direct} {%domain%/includes/} {403}
php {deny} {direct} {%domain%/php/} {403}
index.php {allow} {direct} {%domain%/dashboard/} {200}
html_footer.php {deny} {direct} {%domain%/dashboard/} {404}
html_header.php {deny} {direct} {%domain%/dashboard/} {404}
.htaccess {deny} {direct} {%domain%/dashboard/} {403}
上面的列表实际上是我希望网站运行的一个示例... index.php
文件控制所请求的“文件”并相应地显示它们。 例如, %domain%/get-in-touch/
将在%domain%/includes/
目录中显示contact.php
文件。 调用index.php
直接显示与%domain%/dashboard/
。
以下代码来自我的.htaccess
文件。 请忽略# NN
片段。 这些都是为了您的利益,从而减少了我添加代码段的需要。 我想它也会对您有帮助...如果需要,您可以直接引用行号。
DirectoryIndex index.php # 01
Options All +FollowSymlinks -Indexes # 02
# 03
<IfModule mod_rewrite.c> # 04
RewriteEngine On # 05
#RewriteBase /rogue/ # 06
# 07
RewriteCond %{REQUEST_FILENAME} !-d # 08
RewriteCond %{REQUEST_FILENAME} !-f # 09
RewriteRule ^(.*?)$ index.php [QSA,L] # 10
# 11
RewriteCond %{REQUEST_FILENAME} -d # 12
RewriteRule ^(.*?)(js|image|css|includes|php|files)(.*)$ index.php [QSA,L] # 13
</IfModule> # 14
我注释了第06行,因为该系统似乎不需要它,但我保留了该行以供我自己参考,并且不太可能以后再使用它。 当文件或目录不存在时,第08至10行控制重定向到index.php
,然后由响应文件控制其余文件。 文件夹css/js/fonts/image/includes/php
都存在,因此第12行和第13行阻止对其进行访问,并重定向到index.php
,可以在其中定位“目录”数组,并且可以选择要包含的相关文件。 数组的示例包含在帖子的底部。 第12行和第13行可以移至第08行上方,并且没有任何变化,但是将它们从文件中删除会引发默认的403 Forbidden错误。
删除线08,09,12和13时页面通过加载位于中的文件,打破image
, files
和fonts
目录, MIME type text/html
,但是,任何其他目录中的文件看似不受影响。
第12和13行根据需要执行,直到您请求访问这些目录中的文件为止。 文件被显示,我所有的秘密都暴露给了世界。 结果,某些非常重要的文件会显示给用户。 我想阻止任何人访问我选择拒绝访问的任何文件夹中的文件,并将其重定向到index.php
并显示403
。 我通过在第12行和第13行之间添加RewriteCond %{REQUEST_FILENAME} -f
进行了尝试,但该页面显示为已损坏,无法加载资源。
注意 :我不得不从第02行中删除-Indexes
,因为来自JavaScript文件的文件请求将被拒绝,这样做还阻止了第12和13行按预期的方式进行,无论它们位于何处。
$_INCDIRECTORY = 'includes/';
$_PATHINCLUDES = array(
'dashboard' => array(
'allow' => true,
'path' => $_INCDIRECTORY.'dashboard.php',
// The following must remain FALSE; This value will be changed 'on-the-fly';
'exists' => false,
),
'news' => array(
'allow' => true,
'path' => $_INCDIRECTORY.'news.php',
// The following must remain FALSE; This value will be changed 'on-the-fly';
'exists' => false,
),
'search' => array(
'allow' => true,
'path' => $_INCDIRECTORY.'search.php',
// The following must remain FALSE; This value will be changed 'on-the-fly';
'exists' => false,
),
// Excluded/Denied directories;
'css' => array(
'allow' => false,
'path' => 'css/',
// The following must remain FALSE; This value will be changed 'on-the-fly';
'exists' => false,
),
// Error pages;
'403' => array(
'allow' => true,
'path' => $_INCDIRECTORY.'errors/403.php',
// The following must remain FALSE; This value will be changed 'on-the-fly';
'exists' => false,
),
'404' => array(
'allow' => true,
'path' => $_INCDIRECTORY.'errors/404.php',
// The following must remain FALSE; This value will be changed 'on-the-fly';
'exists' => false,
),
);
在花了一段时间寻找解决方案并尝试了常见的试验和错误尝试之后,我提出了一个完全可以按照我想要的方式工作的解决方案。 回答我自己的问题以供任何遇到相同问题的人参考似乎更合适。
以下代码位于网站根目录下的.htaccess
文件中。 在代码段之后,对每行的功能进行了描述。
DirectoryIndex index.php
Options +FollowSymlinks -Indexes
<IfModule mod_rewrite.c>
# Enable mod_rewrite;
RewriteEngine On
# Detect if SSL Module is enabled;
<IfModule mod_ssl.c>
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,NC,L]
</IfModule>
# Check if the directory exists;
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{HTTP_REFERER} !^((((https|http)://([w]{3}\.)?)([a-z0-9\.]+)/).*)$ [NC]
RewriteRule ^(.*?)(js|image|css|includes|php|files)(.*)$ index.php [L]
# Check if the file exists;
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{HTTP_REFERER} !^((((https|http)://([w]{3}\.)?)([a-z0-9\.]+)/).*)$ [NC]
RewriteRule ^(.*?)(js|image|css|includes|php|files)(.*)$ index.php [L]
# Redirect to 'index.php', regardless of the request;
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*?)$ index.php [QSA,L]
</IfModule>
DirectoryIndex index.php
将网站的主要“主页”定义为index.php
,这不是index.php
,但是如果您的Web主机将Apache的默认设置更改为使用其他默认索引,则使用此方法可能是一个好习惯。
Options +FollowSymlinks -Indexes
执行以下操作: +FollowSymlinks
允许Apache'遵循符号链接',并且-Indexes
防止在缺少索引的情况下列出任何子文件夹。{ext}。 注意 :从以前的配置中删除All
将阻止脚本调用包含在排除项中,从而允许所有AJAX功能。
<IfModule mod_rewrite.c> ... </IfModule>
允许htaccess文件的基础运行,而无需在Apache配置中启用重写模块。
RewriteEngine On
启用重写引擎。 将值设置为“ Off
将禁用此功能,并且所有基础代码都将无法运行。
<IfModule mod_ssl.c> ... </IfModule>
允许所包含的代码运行,前提是Apache安装包括并使用SSL模块。
RewriteCond %{HTTPS} off
然后检查是否%{HTTPS}
正在使用由所述请求,然后RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,NC,L]
将用户永久重定向到启用SSL的URI。 %{HTTP_HOST}%{REQUEST_URI}
仅允许在多个网站上使用相同的功能,而无需重新配置。
RewriteCond %{REQUEST_FILENAME} -d
检查以查看请求的目录是否存在, RewriteCond %{HTTP_REFERER} !^((((https|http)://([w]{3}\\.)?)([a-z0-9\\.]+)/).*)$ [NC]
然后检查是否引荐并没有要求一个完整的URL,基本上是一个域名。 RewriteCond
的RegEx检查请求是否使用http
或https
,还可以选择使用www.
然后检查网址的其余部分。 然后RewriteRule ^(.*?)(js|image|css|includes|php|files)(.*)$ index.php [L]
检查所请求的文件夹是否包含在RegEx中,然后重定向到index.php
,PHP代码将在其中处理棘手的问题。 注意 :请参阅此帖子以供参考。
按照与上述代码相同的过程, RewriteCond %{REQUEST_FILENAME} -f
执行相同的操作。 但是处理文件请求(如果存在)。 注意 :再次,请参阅此帖子以供参考。
RewriteCond %{REQUEST_FILENAME} !-d
和RewriteCond %{REQUEST_FILENAME} !-f
检查所请求的文件是目录还是文件,以及它们是否存在,然后检查RewriteRule ^(.*?)$ index.php [QSA,L]
将整个请求重定向到index.php
,PHP将在其中正确处理该请求。 注意 :对于那些还不知道的人, !
字符在大多数情况下可以作为not
的简写。 注意 :有关mod_rewrite变量备忘单,请参见此页面 。 而此工具用于RegEx测试。
在此处找到该文章之后,创建您的PHP文件,然后在此答案中使用.htaccess
配置似乎可以完美地工作,并提供您可能要求的大多数功能。 在我的情况下,已经对该索引进行了严重修改,下面显示了更重要的修改。
switch( $path_info['call_parts'][0] ) {
case 'about-us':
include 'about.php';
break;
case 'users':
include 'users.php';
break;
case 'news':
include 'news.php';
break;
case 'products':
include 'products.php';
break;
default:
include 'front.php';
break;
}
可以更改以上代码以创建更干净的环境和更易于理解的配置。 由于某些网站功能可以由请求的文件控制,因此建议将代码更改为更合适的替代方法。
例如:您的所有请求都可以添加到包含一些基于请求的变量的数组中。
$_INCDIRECTORY = 'includes/';
$_PATHINCLUDES = array(
'dashboard' => array(
'allow' => true,
'path' => $_INCDIRECTORY.'dashboard.php',
// The following must remain FALSE; This value will be changed 'on-the-fly';
'exists' => false,
),
'news' => array(
'allow' => true,
'path' => $_INCDIRECTORY.'news.php',
// The following must remain FALSE; This value will be changed 'on-the-fly';
'exists' => false,
),
'search' => array(
'allow' => true,
'path' => $_INCDIRECTORY.'search.php',
// The following must remain FALSE; This value will be changed 'on-the-fly';
'exists' => false,
),
'register' => array(
'allow' => true,
'path' => $_INCDIRECTORY.'register.php',
// The following must remain FALSE; This value will be changed 'on-the-fly';
'exists' => false,
),
####################################
## DENIED PAGES/DIRECTORIES ########
####################################
'css' => array(
'allow' => false,
'path' => 'css/',
// The following must remain FALSE; This value will be changed 'on-the-fly';
'exists' => false,
),
'files' => array(
'allow' => false,
'path' => 'files/',
// The following must remain FALSE; This value will be changed 'on-the-fly';
'exists' => false,
),
####################################
## ERROR PAGES #####################
####################################
'403' => array(
'allow' => true,
'path' => $_INCDIRECTORY.'errors/403.php',
// The following must remain FALSE; This value will be changed 'on-the-fly';
'exists' => false,
),
'404' => array(
'allow' => true,
'path' => $_INCDIRECTORY.'errors/404.php',
// The following must remain FALSE; This value will be changed 'on-the-fly';
'exists' => false,
),
);
初始数组包含请求的每个文件或目录的列表。 然后,每个子数组都包含特定于请求的变量,这些变量稍后将控制包含脚本。 'allow'
定义是否允许用户查看请求。 true将显示页面,而false将显示403错误。 'path'
定义了脚本请求的文件,其他代码段检查了该文件是否存在,然后显示为绿色。 在请求开始时, 'exists'
始终为假,随后将进行更改。
foreach( $_PATHINCLUDES as $key => &$value ) {
## Check to see if browsing the 'directory' is allowed
## before checking to see if the 'directory' exists;
if( $value['allow'] == true ) {
## Browsing is allowed, check if 'directory'
## actually exists and set 'exists' to '=1';
if( file_exists( $value['path'] ) == true ) {
## Set the value 'exists' to 'true';
$value['exists'] = true;
};
} else {
## Browsing the 'directory' is not allowed,
## so the response should be a '403';
};
};
unset( $value );
上面的代码处理该数组,并相应地将'exists'
为true或false 。 提供'allow'
变量为true 。 当文件夹/文件的存在无关紧要时,检查用户无法访问的文件夹/文件毫无意义。 .. as $key => &$value ..
允许在foreach( .. )
循环中更改数组的值, unset( $value );
从循环之后的任何操作中删除该变量。 注意 :请参阅此帖子以供参考。
为了防止任何讨厌的PHP错误,例如未设置请求的offset [N]等,请使用以下代码。 这将在尝试使用变量之前检查该变量是否确实存在,如果不存在,则使用预定义的值。
$_CALL_PART = isset( $path_info['call_parts'][0] ) ? $path_info['call_parts'][0] : 'dashboard';
$_REQUESTED = isset( $_PATHINCLUDES[ $_CALL_PART ] ) ? $_PATHINCLUDES[ $_CALL_PART ] : $_PATHINCLUDES['404'];
最终代码段控制着所包含文件的行为。
## Check to see if access to the file is
## allowed before doing anything else;
if( $_REQUESTED['allow'] == true ) {
## The file can be browsed to, so check if it exists;
if( $_REQUESTED['exists'] == true ) {
## The file exists, so include it;
include( $_REQUESTED['path'] );
} else {
## The file does not exist, so display a 404 page;
if( $_PATHINCLUDES['404']['exists'] == true ) {
## Check to ensure the file exists before including it;
## This prevents an error;
include( $_PATHINCLUDES['404']['path'] );
} else {
## The file does not exist, so simply display a message;
echo '<h1>404 - File Not Found: No ErrorDocument supplied</h1>';
};
};
} else {
## The file cannot be browsed to, so display a 403;
if( $_PATHINCLUDES['403']['exists'] == true ) {
## Check to ensure the file exists before including it;
## This prevents an error;
include( $_PATHINCLUDES['403']['path'] );
} else {
## The file does not exist, so simply display a message;
echo '<h1>403 - Forbidden: No ErrorDocument supplied</h1>';
};
};
if( $_REQUESTED['allow'] == true ) { ... } else { ... }
检查是否允许该请求。 如果是这样,可以执行脚本的下一部分。 if( $_REQUESTED['exists'] == true ) { ... } else { ... }
检查请求的文件是否存在。 如果是这样,脚本将执行include( $_REQUESTED['path'] );
显示页面。 否则,脚本然后返回404,随后以相同的方式检查此文本(不包括allow
参数),然后显示它。 如果先前的if( .. )
语句返回true ,则将在exists
参数返回为true的情况下检查并显示403错误。 如果找不到403
和404
页面,则脚本将显示基本错误响应。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.