flawopen.com/文件包含/PHP include()
PHP include() 使用用户输入安全吗?
不安全。include() 会将选定文件按 PHP 解析,但影响取决于可访问的文件及其内容。缺陷可能通过 wrapper 暴露源代码、包含意外的本地文件;只有攻击者能控制带 PHP 标签的内容且应用随后包含该文件时,才会执行其 PHP 代码。远程 URL 包含还取决于 PHP 配置。将用户选择映射到固定键列表,切勿用请求数据拼接 include 路径。
<?php // User-controlled path: unintended local file include $_GET['page'] . '.php'; // Example selector: ../../private/sample // Impact depends on the resolved file and // whether it contains PHP code to interpret. // Remote URL inclusion requires the relevant // URL wrapper and allow_url_include setting. // Wrappers can change which resource is read; // php://filter is a read filter, not a path // containment check.
<?php // Allowlist: input selects a KEY, // never a path or wrapper. $pages = [ 'home' => __DIR__ . '/pages/home.php', 'about' => __DIR__ . '/pages/about.php', 'contact' => __DIR__ . '/pages/contact.php', ]; $key = $_GET['page'] ?? 'home'; if (!is_string($key) || !array_key_exists($key, $pages)) { http_response_code(404); exit; } include $pages[$key];
为什么本地包含不等于自动执行代码
本地包含不会自动执行代码。PHP 会解析被包含文件:有效 PHP 标签内的语句在包含上下文中执行,其他字节可能作为输出发送。代码执行需要可访问的攻击者可控 PHP 文件或其他可利用行为。例如,上传或日志写入缺陷可能形成攻击链:将可控 PHP 内容写入之后会被包含的文件。
php://filter 会在打开流时应用过滤器。在存在漏洞的读取或包含流程中,合适的过滤器可能暴露源文本而不执行它;能否读取取决于 wrapper、权限和应用配置。
为什么清理路径不是正确修复
删除 ../、追加固定扩展名或添加目录前缀都不能证明最终资源已获准。编码、绝对路径、平台规则和 wrapper 都可能改变解释方式。应移除用户对资源名称的控制:只允许选择应用定义的固定键。
如果必须解析文件系统路径,请用 realpath() 规范化,并按 Path Traversal 指南检查目录边界。随后仅允许预先批准的文件,同时考虑符号链接和检查后使用竞态。固定目标允许列表更安全。
常见问题
此设置会为 include/require 禁用 URL wrapper。PHP 文档说明它默认关闭,并自 PHP 7.4 起弃用。这能降低远程包含风险,但不能阻止本地路径遍历或不安全的本地包含。保持关闭,并移除用户对目标的控制。
PHP 5.3.4 修复了路径处理中的空字节截断。不要把旧技巧失效当作防护;不可信的 include 目标仍然危险。
require 和 _once 变体也会包含并解析目标;它们在失败和重复包含处理上有所不同,但不会让不可信目标变安全。readfile() 和 file_get_contents() 返回数据,不会按 PHP 解析;不可信路径可能造成遍历或泄露,而非 include 代码执行。