最可靠的防御方式是彻底切断用户输入与文件路径的拼接关系,采用预定义键值对白名单替代动态拼接,严格校验参数存在性、类型和长度,加载前用realpath()验证路径合法性,并配合php.ini安全配置协同加固。

最可靠、最直接的防御方式,就是彻底切断用户输入和文件路径之间的拼接关系。白名单机制不是“加一层过滤”,而是用预定义的映射关系替代动态路径构造,从逻辑上消除可控路径的可能性。
明确白名单结构:用键值对代替字符串拼接
不要写 include($_GET['page'] . '.php') 这类代码。改为预先定义一个数组,把合法参数和对应的真实文件路径一一绑定:
- 键(key)是用户可传的标识符,比如
'home'、'about'、'contact' - 值(value)是服务器上绝对路径或相对于入口文件的固定路径,如
__DIR__ . '/pages/home.php' - 接收参数后,只做数组键查找,不进行任何字符串操作或路径拼接
- 查不到就中止,不 fallback、不默认、不猜测
严格校验与安全加载
拿到参数后不能直接当数组下标用,需确保它符合预期类型和范围:
- 用
isset()或array_key_exists()判断键是否存在,避免未定义索引警告暴露逻辑 - 强制转换为字符串并限制长度(如
substr($page, 0, 32)),防超长键绕过或日志污染 - 加载前调用
realpath()验证路径是否真实存在且在预期目录内(可配合str_starts_with()检查前缀) - 最终执行
include时,只传白名单中取出的完整路径,绝不二次拼接
配合环境配置加固效果
白名单是代码层核心防线,但需和 PHP 运行时配置协同生效:
- 在
php.ini中设置allow_url_include = Off,彻底禁用远程包含 - 启用
open_basedir限制脚本只能访问指定目录树,缩小攻击面 - 禁用危险函数如
eval、assert、create_function,防止伪协议载荷落地后进一步利用 - 生产环境关闭
display_errors,避免报错信息泄露路径结构
避免常见误区
白名单容易写,但细节决定成败:
- 不要用
in_array()查找用户输入——它会触发松散比较,'1'可能匹配到1或true - 不要在白名单数组里存相对路径如
'pages/home.php'后再拼include $whitelist[$page]——若没做路径规范化,仍可能被../穿透 - 不要把白名单数组放在可被覆盖的变量作用域里(如全局变量、可被
extract()注入的数组) - 语言包、模板、主题切换等高频漏洞场景,同样适用该模式,只需扩展键值对即可
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











