以下是一个使用 PHP 和 MySQL 实现的安全用户认证和权限管理的示例,包括修复修改 cookie 中 is_admin 值的漏洞。


---

完整实现流程

1. 数据库设计

一个简单的用户表(users)和会话表(sessions):

CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
is_admin BOOLEAN NOT NULL DEFAULT 0
);

CREATE TABLE sessions (
id CHAR(64) PRIMARY KEY, -- 会话 ID
user_id INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);

users 表存储用户信息,包括是否管理员 (is_admin)。

sessions 表存储会话信息,使用随机生成的 session_id 关联用户。



---

2. 用户登录逻辑

<?php
session_start();
include 'db.php'; // 数据库连接文件

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'];
$password = $_POST['password'];

// 查询用户
$stmt = $db->prepare("SELECT id, password_hash, is_admin FROM users WHERE username = ?");
$stmt->bind_param("s", $username);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();

if ($user && password_verify($password, $user['password_hash'])) {
// 登录成功,生成会话
$session_id = bin2hex(random_bytes(32)); // 生成随机会话 ID
$stmt = $db->prepare("INSERT INTO sessions (id, user_id) VALUES (?, ?)");
$stmt->bind_param("si", $session_id, $user['id']);
$stmt->execute();

// 设置安全的 cookie
setcookie('session_id', $session_id, [
'httponly' => true,
'secure' => true,
'samesite' => 'Strict'
]);

echo "Login successful!";
} else {
echo "Invalid username or password.";
}
}
?>


---

3. 后台访问逻辑

<?php
session_start();
include 'db.php'; // 数据库连接文件

if (!isset($_COOKIE['session_id'])) {
die("Unauthorized access.");
}

$session_id = $_COOKIE['session_id'];

// 验证会话并获取用户信息
$stmt = $db->prepare("
SELECT u.id, u.username, u.is_admin
FROM sessions s
JOIN users u ON s.user_id = u.id
WHERE s.id = ?
");
$stmt->bind_param("s", $session_id);
$stmt->execute();
$result = $stmt->get_result();
$user = $result->fetch_assoc();

if (!$user) {
die("Invalid session.");
}

if (!$user['is_admin']) {
die("Forbidden: You don't have permission to access this page.");
}

// 如果通过验证,显示后台内容
echo "Welcome to the admin dashboard, " . htmlspecialchars($user['username']) . "!";
?>


---

4. 登出逻辑

<?php
session_start();
include 'db.php'; // 数据库连接文件

if (isset($_COOKIE['session_id'])) {
$session_id = $_COOKIE['session_id'];

// 删除会话记录
$stmt = $db->prepare("DELETE FROM sessions WHERE id = ?");
$stmt->bind_param("s", $session_id);
$stmt->execute();

// 清除 cookie
setcookie('session_id', '', time() - 3600, '/');
}

echo "Logged out successfully.";
?>


---

关键点说明

1. 会话管理:

会话 ID (session_id) 是随机生成的,攻击者无法轻易猜测。

会话信息保存在服务端数据库中,不依赖客户端数据。



2. 权限校验:

后端根据 session_id 查询用户权限 (is_admin),而非直接信任客户端传递的 is_admin 值。



3. 密码存储:

使用 password_hash() 和 password_verify() 安全地处理密码。



4. Cookie 安全性:

设置 HttpOnly 和 Secure 标志,防止 XSS 和中间人攻击。

SameSite=Strict 防止 CSRF 攻击。



5. 输入验证:

使用 prepared statements 防止 SQL 注入。

避免直接输出用户输入内容,使用 htmlspecialchars() 进行输出过滤。





---

运行逻辑示例

1. 用户登录:

用户提供用户名和密码。

系统验证密码并生成安全的 session_id。

session_id 存储在服务端数据库,并通过 cookie 传递给客户端。



2. 后台访问:

用户发起请求时,系统验证 session_id 的合法性。

根据数据库中用户的 is_admin 字段判断权限。



3. 权限不足:

如果用户 is_admin 为 0,拒绝访问后台。





---

总结

通过以上方式修复漏洞,可以确保即使攻击者篡改 cookie,也无法获得管理员权限,因为权限验证完全在后端进行,依赖于服务端的安全存储和验证逻辑。
 
 
Back to Top