下面给你一份 《PHP 文件读取漏洞剖析及防御方法》完整指南(含原理 + 利用方式 + 防御代码),内容结构清晰、直接可用于学习、写文档或输出到你的网站。
🛡 PHP 文件读取漏洞剖析及防御方法(完整指南)
PHP 中的文件读取相关函数非常常见,如:
file_get_contents()
fopen()
readfile()
include / require
include_once / require_once
如果开发时处理不当,就会出现 任意文件读取漏洞(LFI),并可能导致信息泄露、代码执行、服务被攻破。
本文将系统解释产生原因、攻击方式、真实利用案例,并提供全面的防御策略。
📌 1. 什么是文件读取漏洞?
文件读取漏洞(LFI) 指攻击者通过可控参数,让服务器读取任意路径下的文件,如:
/etc/passwd- 网站的
.env - 配置文件
- 源代码文件
- session 文件
- nginx/apache 配置等
典型例子(漏洞代码):
<?php
$file = $_GET['file'];
echo file_get_contents($file);
?>
攻击者直接访问:
http://site.com/read.php?file=/etc/passwd
即可读取系统文件。这就是 LFI。
📌 2. 常见的文件读取方式与对应漏洞
✦ 2.1 使用 file_get_contents 读取任意文件(最常见)
file_get_contents($_GET['path']);
攻击:
?path=/etc/passwd
✦ 2.2 include / require 导致代码执行
include $_GET['page'];
攻击者可以:
- 读取文件内容
- 执行恶意代码
如:
?page=php://input
然后 POST malicious code。
✦ 2.3 目录穿越漏洞 (../)
攻击者利用:
?file=../../../../etc/passwd
穿越目录读取敏感文件。
✦ 2.4 PHP stream wrapper 绕过过滤
即使你限制了 “不能出现 ../”,攻击者仍可使用:
| Wrapper | 作用 |
|---|---|
php://filter | 读取源码(绕过 include 执行) |
php://input | 注入代码执行 |
data:// | 执行脚本 |
file:// | 重新访问系统文件 |
compress.zlib:// | 访问压缩文件 |
例如读取 PHP 源码:
?page=php://filter/convert.base64-encode/resource=index.php
网站源码被完整泄露。
📌 3. 文件读取漏洞的利用方式(黑客能做到什么)
攻击者可利用漏洞:
✔ 3.1 读取敏感系统文件
/etc/passwd
/etc/hosts
/proc/self/environ
✔ 3.2 读取数据库密码 .env、配置 .ini
/var/www/html/.env
config.php
wp-config.php
✔ 3.3 读取 session 文件 → 登录后台
✔ 3.4 通过 include 直接执行恶意代码(RCE)
结合:
php://input
data://
攻击者可以获得服务器权限。
📌 4. 文件读取漏洞真实案例
真实生产环境中最常见例子:
❌ 错误代码
$file = $_GET["page"];
include $file;
攻击方式:
① 读取 PHP 源码:
?page=php://filter/convert.base64-encode/resource=index.php
② 远程执行代码:
?page=php://input
POST 数据:
<?php system('id'); ?>
服务器权限被拿下。
📌 5. 如何彻底防御 PHP 文件读取漏洞?
这是最重要部分!下面给你最佳防御策略 + 代码示例。
✔ 5.1 不要直接使用用户输入的路径
$file = $_GET['file'];
file_get_contents($file); // ❌ 非常危险
✓ 必须做 白名单 或 固定目录限制
✔ 5.2 使用白名单(最有效)
$allow = [
"about.html",
"contact.html",
"help.html"
];
$file = $_GET["file"];
if (!in_array($file, $allow)) {
die("Access denied");
}
echo file_get_contents("pages/" . $file);
✔ 5.3 限制目录:禁止跳出指定目录(realpath)
$base = realpath("./uploads");
$path = realpath($base . "/" . $_GET['file']);
if (strpos($path, $base) !== 0) {
die("Invalid path");
}
echo file_get_contents($path);
✔ 5.4 禁止 wrapper(强烈建议)
if (preg_match('/^php:\/\/|^data:|^compress\.zlib:|^phar:|^glob:/i', $_GET['file'])) {
die("Illegal wrapper");
}
✔ 5.5 禁止出现目录穿越 (../)
if (strpos($_GET['file'], "..") !== false) {
die("Illegal path");
}
✔ 5.6 include/require 只能用于 固定文件
不要这样:
include $_GET['page']; // ❌
要这样:
include "pages/" . $page . ".php"; // ✔ 不可随意跳目录
✔ 5.7 权限隔离
- uploads 目录无执行权限
- PHP 代码目录不允许写入
- 限制 www-data 访问文件的能力
即使有漏洞,也不至于严重破坏。
📌 6. 一套“安全的文件读取函数”(你可直接用)
function safe_file_read($filename) {
$base = realpath(__DIR__ . "/safe_files");
// 禁止协议流
if (preg_match('/^php:\/\/|^data:|^phar:|^zip:|^glob:/i', $filename)) {
return false;
}
// 禁止 ../
if (strpos($filename, "..") !== false) {
return false;
}
$path = realpath($base . "/" . $filename);
// 必须在安全目录内
if ($path === false || strpos($path, $base) !== 0) {
return false;
}
return file_get_contents($path);
}
使用:
echo safe_file_read($_GET["file"]);
📌 7. 总结(适合写文档与面试)
PHP 文件读取漏洞产生原因:
- 未过滤用户输入
- 未限制目录范围
- wrapper 绕过
- include/require 组合导致 RCE
防御重点:
- 白名单
- realpath + 目录限制
- 禁止 wrapper
- 禁止 ../
- 目录权限隔离
这套组合可防御 99% 文件读取攻击。
发表回复