
本文介绍在web应用中使用get方法传递id查询数据库时,防止用户篡改url参数访问他人数据的安全实践,重点讲解基于会话(session)的权限校验机制与防篡改设计。
本文介绍在web应用中使用get方法传递id查询数据库时,防止用户篡改url参数访问他人数据的安全实践,重点讲解基于会话(session)的权限校验机制与防篡改设计。
在学生项目或中小型Web应用中,常见流程是:表单提交 → 数据入库 → 重定向至摘要页(如 summary.php?id=123),并通过 $_GET['id'] 查询并展示刚提交的记录。但直接暴露且未校验的ID参数存在严重安全隐患——用户只需手动修改URL中的 id 值(如改为 ?id=124),即可越权查看他人数据。
核心原则:绝不信任客户端输入$_GET['id'] 是完全可控的外部输入,不能作为权限判断的唯一依据。必须引入服务端状态管理,确保“当前用户只能访问其本人的数据”。
✅ 推荐方案:结合 Session 与数据库权限校验
-
提交成功后,将本次操作的记录ID与用户标识(如登录ID或唯一会话凭证)一同存入Session:
// form_handler.php(处理表单后) $stmt = $pdo->prepare("INSERT INTO submissions (user_id, content) VALUES (?, ?)"); $stmt->execute([$_SESSION['user_id'], $content]); $new_id = $pdo->lastInsertId();
// 关联该ID到当前会话,仅允许本次会话访问 $_SESSION['allowed_summary_id'] = $new_id; header("Location: summary.php"); exit;
2. **在 `summary.php` 中严格校验:不仅验证ID存在,更验证是否属于当前会话**:
```php
// summary.php
if (!isset($_SESSION['allowed_summary_id'])) {
http_response_code(403);
die("Access denied: No valid session context.");
}
$allowed_id = (int)$_SESSION['allowed_summary_id'];
// 清除一次性的会话标记(防重复访问)
unset($_SESSION['allowed_summary_id']);
// 查询时强制关联用户身份(双重保险)
$stmt = $pdo->prepare("
SELECT * FROM submissions
WHERE id = ? AND user_id = ?
");
$stmt->execute([$allowed_id, $_SESSION['user_id']]);
$result = $stmt->fetch();
if (!$result) {
http_response_code(404);
die("Record not found or access denied.");
}
⚠️ 注意事项:
-
禁用“纯ID路由”:避免
summary.php?id=123这类无状态URL作为入口;应统一由受控跳转触发(如上例中不带GET参数的重定向)。 -
Session需启用且安全配置:确保
session_start()正确调用,session.cookie_httponly和session.cookie_secure(HTTPS环境)开启。 - 不要依赖非顺序ID(如UUID)作为安全措施:这仅增加猜测难度,不属于权限控制,仍属“安全错觉”。
- 扩展建议:生产环境可升级为JWT令牌或短期有效的单次访问Token,但对教学项目,Session方案简洁、可靠、易理解。
总结:安全的本质不是隐藏ID,而是建立“谁(Who)能看什么(What)”的服务端契约。每一次敏感数据查询,都必须同时验证用户身份与资源归属关系——这是Web权限控制不可妥协的底线。










