PHP页面存在性检查、GET包含错误捕获及防盲注方案问询
一、解决用户修改page参数导致报错的问题
哥们,用户随便改page参数就报错,核心是你没对传入的参数做安全校验与边界控制,直接引入要么文件不存在,要么被恶意利用(比如目录遍历)。给你两个靠谱的解决方案:
1. 用白名单做严格验证(最安全)
只允许预设的页面被访问,其他参数直接跳转到默认页或404:
// 定义允许访问的页面列表(根据你的实际业务调整) $allowed_pages = ['home', 'about', 'dashboard', 'profile']; // 获取page参数,默认值设为首页 $page = $_GET['page'] ?? 'home'; // 检查参数是否在白名单内,不在就强制走错误流程 if (!in_array($page, $allowed_pages)) { // 可选:返回404状态码 header("HTTP/1.0 404 Not Found"); include __DIR__ . '/pages/404.php'; exit; } // 拼接安全的文件路径(假设页面都放在pages目录下) $file_path = __DIR__ . '/pages/' . basename($page) . '.php'; // 最后再确认文件存在,避免意外报错 if (file_exists($file_path)) { include $file_path; } else { include __DIR__ . '/pages/404.php'; }
2. 限制文件访问范围(适合页面较多的场景)
如果白名单不好维护,至少要确保引入的文件在指定目录内,防止目录遍历攻击:
$page = $_GET['page'] ?? 'home'; $base_dir = realpath(__DIR__ . '/pages/'); $file_path = realpath($base_dir . '/' . $page . '.php'); // 检查文件是否在允许的目录内,且确实存在 if ($file_path && str_starts_with($file_path, $base_dir) && file_exists($file_path)) { include $file_path; } else { include __DIR__ . '/pages/404.php'; }
这样就算用户传../secret/config.php,realpath会解析成真实路径,只要不在pages目录下就会被拒绝。
二、除预处理语句外,防范盲SQL注入的方法
mysqli_real_escape_string确实有局限性(比如依赖字符集、必须正确包裹引号才有效),除了预处理,这些方法也能有效防盲注:
强制类型转换:如果参数是数字类型(比如ID、页码),直接转成整数:
$user_id = (int)$_GET['user_id']; // 或者先验证再转,更严谨 if (ctype_digit($_GET['user_id'])) { $user_id = (int)$_GET['user_id']; } else { // 处理非法输入 }不管传什么恶意字符串,都会变成数字,根本没法注入。
枚举值白名单:如果参数是固定选项(比如排序字段、状态),只允许预设的值:
$allowed_sort = ['id', 'username', 'create_time']; $sort_by = $_GET['sort'] ?? 'id'; if (!in_array($sort_by, $allowed_sort)) { $sort_by = 'id'; } // 之后拼接SQL时用$sort_by就安全了数据库最小权限原则:给应用的数据库用户分配最小必要权限,比如查询页面的用户只给
SELECT权限,不能有INSERT、DELETE、DROP等权限。就算发生注入,攻击者也干不了太多坏事。避免动态拼接SQL结构:绝对不要用用户输入直接拼接表名、列名这类SQL结构。如果必须动态处理,一定要用白名单控制,不能直接把用户输入拼进去。
使用ORM框架:比如Laravel的Eloquent、Doctrine这些ORM,内部会自动处理SQL的安全拼接,只要你不用原生SQL硬拼用户输入,就能大幅降低注入风险。
输入长度限制:对用户输入做长度截断,比如用户名最多20字符,邮箱最多50字符,减少注入payload的长度,降低成功注入的概率。
内容的提问来源于stack exchange,提问作者John Lee

