本文将详细说明:在 Web 应用中通过 GET 参数传递 ID 查询数据库时,如何有效防止用户篡改 URL 中的 ID,进而非法查看他人数据。文章重点围绕基于会话(Session)的身份验证与权限控制机制,帮助你安全实现数据库查询并避免 ID 越权访问问题。

本文将详细说明:在 Web 应用中通过 GET 参数传递 ID 查询数据库时,如何有效防止用户篡改 URL 中的 ID,进而非法访问或读取他人数据。文章重点介绍基于会话(Session)的登录校验与访问权限控制方案。
在实际开发过程中,很多初学者都会直接使用类似 summary.php?id=123 的方式,通过 GET 参数查询数据库记录。表面上看,这种写法简单直接、实现成本低,但安全隐患也非常明显:它极易导致严重的越权访问(Insecure Direct Object Reference, IDOR)漏洞。更直白地说,用户只需要修改 URL 中的 id 参数,例如把 id=123 改成 id=124,就可能尝试访问其他用户的敏感信息。无论是练手项目、后台管理系统,还是正式上线的业务平台,这类问题都属于高风险安全漏洞。
✅ 真正安全的做法,不是单纯隐藏、混淆或替换 ID(例如改成 UUID、哈希值等),而是在服务端强制执行访问控制:每一次请求都必须验证“当前登录用户是否确实有权限查看该 ID 对应的数据记录”。
核心解决方案:服务端会话 + 权限绑定
- 表单提交完成后,将用户对应的数据 ID 安全绑定到 Session 中
在数据写入成功并执行跳转之前,把新生成的记录 ID 与当前用户身份标识(如$_SESSION['user_id'])一起保存到服务端 Session 中:
// process_form.php(表单处理页)
if ($insert_success) {
$_SESSION['last_submission_id'] = $new_record_id; // 仅存储本次操作ID
$_SESSION['user_id'] = $current_user_id; // 确保已登录且有用户身份
header('Location: summary.php');
exit;
}- 在 summary.php 中,不再把 GET 参数作为唯一依据,改用 Session 中的 ID 进行校验
不要继续信任$_GET['id'],而应从 Session 中读取允许访问的 ID,并进行双重验证:- 该 ID 是否真实存在于 Session 中;
- 该 ID 对应记录的
user_id字段是否与当前登录用户 ID 完全一致。
// summary.php
session_start();
// 1. 强制登录检查
if (!isset($_SESSION['user_id'])) {
die('Access denied: Not logged in.');
}
$allowed_id = $_SESSION['last_submission_id'] ?? null;
if (!$allowed_id) {
die('Access denied: No valid submission found.');
}
// 2. 数据库查询:必须关联用户身份
$stmt = $pdo->prepare("
SELECT * FROM submissions
WHERE id = ? AND user_id = ?
");
$stmt->execute([$allowed_id, $_SESSION['user_id']]);
$record = $stmt->fetch();
if (!$record) {
die('Access denied: Record not found or unauthorized.');
}
// 安全输出数据
echo "Your Submission
";
echo "Name: " . htmlspecialchars($record['name']) . "
";
// ... 其他字段⚠️ 关键注意事项
- 绝不要依赖客户端可控参数进行权限判断:无论是
$_GET['id']、$_COOKIE,还是前端隐藏表单字段,本质上都可以被用户篡改。真正可信的只有服务端 Session 与数据库层面的归属校验。 - Session 必须正确配置:确保启用
session_start(),设置合理的会话超时时间(ini_set('session.gc_maxlifetime', 1800)),并通过 HTTPS 安全传输 Cookie(session_set_cookie_params(['secure' => true, 'httponly' => true])),从而提升整体账户安全性。 - 避免“看似安全”的伪修复方案:仅使用非连续 ID(如 UUID)、MD5 哈希 ID,或者依赖 Referer 检查,并不能真正阻止恶意用户主动枚举和探测资源,这些方式都不能作为有效的权限防护手段。
- 扩展建议:如果业务场景涉及多条记录查询,例如用户历史记录、订单列表、资料详情页等,SQL 语句中都应始终明确加入
WHERE user_id = ?这类归属条件,而不是仅依赖前端传入的记录 ID。
总结:数据库查询的安全关键,不在于让 ID 变得“更难猜”,而在于确保每一次访问请求都经过身份认证 + 数据归属授权的双重校验。只有把业务逻辑与权限控制真正放在服务端并严格绑定,才能从根本上防止 GET 参数导致的 ID 越权访问漏洞。
