php://filter伪协议能读取php源码是因为它作为流包装器,在文件包含过程中拦截了数据流,允许对经过过滤器的数据进行预处理。配合base64编码可以将php代码中的特殊字符(如引号、反斜杠)进行编码,从而绕过waf或安全限制,将源码以明文形式输出到页面中。

php://filter如何拦截并处理数据流
php://filter是一个内置的流包装器,它允许你在打开文件时应用过滤器。当使用include或require等函数时,如果传入的文件路径包含php://filter/...,PHP引擎会先执行过滤器逻辑,然后再将结果传递给包含机制。默认情况下,如果不指定过滤器,数据会被原样读取。但通过指定read=convert.base64-encode,数据会在被包含之前先经过base64编码,然后这个编码后的字符串才会被当作普通文本包含进来,最终显示在浏览器上。

<?php // 假设存在一个文件 test.php
// 内容: <?php echo "Hello World"; ?>
// 攻击者构造的URL参数
$file = $_GET['file'];
// 简单的文件包含逻辑
if (isset($file)) {
include($file);
}
?>
预期结果:访问 ?file=php://filter/read=convert.base64-encode/resource=test.php 会在页面上输出类似 PD9waHAgZWNobyAiSGVsbG8gV29ybGQiOyA/Pg== 的字符串,这是test.php内容的base64编码。
base64编码在绕过安全限制中的作用
base64编码在这里的主要作用是转义PHP代码中的敏感字符。许多Web应用防火墙(WAF)或安全脚本会检查请求中是否包含 或 eval() 等危险关键字。由于base64编码后的字符串只包含字母、数字和符号 =、+、/,这些字符通常不会被WAF视为恶意负载。因此,即使服务器配置了某些基于关键字的检测规则,攻击者仍然可以通过这种方式获取源码。此外,base64编码还可以防止因PHP代码中包含单引号、双引号或反斜杠而导致的语法错误或解析失败,确保数据能够完整地被读取和显示。

<?php // 模拟一个简单的WAF检测
$request_uri = $_SERVER['REQUEST_URI'];
$blacklist = ['<?php', 'eval(', 'system('];
foreach ($blacklist as $word) {
if (stripos($request_uri, $word) !== false) {
die('Access Denied');
}
}
// 如果未被拦截,则继续执行文件包含
$file = $_GET['file'];
if (isset($file)) {
include($file);
}
?>
预期结果:直接访问 ?file=test.php 会正常执行;访问 ?file=php://filter/read=convert.base64-encode/resource=test.php 会绕过WAF检测,因为URL中没有黑关键字,且最终输出的是编码后的字符串,不会触发基于源代码内容的检测。
当resource参数指向不存在的文件时会发生什么
当 resource 参数指向一个不存在的文件时,php://filter 会尝试打开该文件。如果文件不存在,PHP通常会抛出一个警告(Warning),提示文件未找到。然而,在某些配置下,如果错误报告级别设置得较低,或者应用程序捕获了异常,可能不会直接显示错误信息。更重要的是,即使文件不存在,php://filter 本身的行为是尝试读取资源。如果资源不可读,过滤器链可能会中断,导致没有输出或输出空字符串。在某些特定的PHP版本或配置中,如果启用了 allow_url_include 并且目标是一个远程资源,行为可能会有所不同,但对于本地文件系统,主要结果是失败并可能伴随错误日志记录。为了验证这一点,我们可以测试一个明显不存在的文件路径。
<?php // 测试不存在的文件
$file = 'php://filter/read=convert.base64-encode/resource=non_existent_file.php';
try {
// 注意:include 不会抛出异常,只会产生警告
// 为了观察行为,我们暂时抑制警告
@include($file);
} catch (Exception $e) {
echo 'Exception: ' . $e->getMessage();
}
?>
预期结果:页面上可能没有任何输出,或者显示一个PHP警告(取决于 display_errors 设置)。错误日志中会记录类似 “Failed opening 'php://filter/read=convert.base64-encode/resource=non_existent_file.php' for inclusion” 的信息。这证明了php://filter依赖于底层文件的可用性,如果文件不存在,读取操作无法完成,也就无法获取源码。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











