如何防止恶意利用RewriteRule访问/home/以外的目录?
路径遍历漏洞的防范方案
我们的网站通过mod_rewrite的RewriteRule规则,将形如example.org/home/products/widgets/的目录请求转换为example.org/home/index.php?path=/products/widgets/的请求,当前使用的规则如下:
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^(.+)/$ ./index.php?path=$1 [NC,QSD,NS] </IfModule>
index.php会列出对应真实目录下的文件详情,但存在安全隐患:攻击者可以构造example.org/home/index.php?path=/products/../../secretstuff这类请求,绕过限制访问/home/以外的目录。
下面是可靠的检测和防范方案,两种方式可以结合使用:
一、用mod_rewrite做前置拦截
可以在现有规则里增加过滤条件,直接拦截包含../的恶意请求,同时限制请求路径的范围:
修改后的规则示例:
<IfModule mod_rewrite.c> RewriteEngine On # 拦截包含../的请求,直接返回403禁止访问 RewriteCond %{QUERY_STRING} (\.\./)+ [NC] RewriteRule ^ - [R=403,L] # 保留原有的目录转index.php规则 RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^(.+)/$ ./index.php?path=$1 [NC,QSD,NS] </IfModule>
这种方式能在请求到达PHP代码前就拦下大部分简单攻击,但要注意攻击者可能用URL编码(比如%2e%2e%2f)绕过,所以这只能作为第一道防线,不能完全依赖。
二、PHP代码用realpath()做核心验证(最可靠)
仅靠mod_rewrite不够彻底,必须在PHP代码层做严格验证,这是解决问题的关键:
- 先确定允许访问的根目录(比如
/home/的绝对路径) - 把用户传入的
path参数和允许目录拼接,用realpath()解析成真实的绝对路径 - 检查解析后的路径是否完全在允许目录范围内
示例代码:
<?php // 定义允许访问的根目录,换成你实际的绝对路径 $allowedRoot = realpath($_SERVER['DOCUMENT_ROOT'] . '/home/'); $requestPath = $_GET['path'] ?? ''; // 拼接并解析真实路径 $targetPath = realpath($allowedRoot . '/' . $requestPath); // 验证路径是否合法:必须存在且在允许的根目录内 if (!$targetPath || strpos($targetPath, $allowedRoot) !== 0) { http_response_code(403); exit('非法访问'); } // 后续逻辑:列出$targetPath下的文件详情 ?>
realpath()会自动处理所有相对路径(比如../、.),转换成真实的绝对路径,不管攻击者用什么方式构造路径,都能准确判断是否越权,这是最可靠的防护手段。
总的来说,建议同时使用两种方式:mod_rewrite拦截大部分恶意请求,减轻后端压力;PHP代码层的验证作为核心,彻底杜绝路径遍历风险。
内容的提问来源于stack exchange,提问作者GrahamS
相关产品推荐
相关产品推荐

