题目
实现安全的用户登录功能
信息
- 类型:问答
- 难度:⭐⭐
考点
表单安全处理,密码验证机制,会话管理
快速回答
实现安全登录功能的关键要点:
- 使用预处理语句防止SQL注入
- 密码采用password_hash()存储,用password_verify()验证
- 登录成功时生成新的会话ID并存储用户ID
- 设置合理的会话过期时间和安全参数
- 对登录失败次数进行限制
核心原理说明
安全的登录系统需要防范多种攻击:SQL注入、密码破解、会话劫持等。PHP提供了内置函数和扩展来帮助实现这些安全措施。
完整代码示例
<?php
// 数据库连接(使用PDO预处理)
$pdo = new PDO('mysql:host=localhost;dbname=test;charset=utf8', 'user', 'pass');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
// 1. 查询用户(防SQL注入)
$stmt = $pdo->prepare("SELECT id, password FROM users WHERE username = ?");
$stmt->execute([$username]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
// 2. 密码验证
if ($user && password_verify($password, $user['password'])) {
// 3. 会话安全设置
session_start();
session_regenerate_id(true); // 防止会话固定攻击
$_SESSION['user_id'] = $user['id'];
$_SESSION['login_time'] = time();
// 4. 设置安全Cookie参数
$cookieParams = session_get_cookie_params();
setcookie(
session_name(),
session_id(),
time() + 3600, // 1小时过期
$cookieParams['path'],
$cookieParams['domain'],
true, // 仅HTTPS
true // HttpOnly
);
header('Location: /dashboard.php');
exit;
} else {
// 登录失败处理
$error = 'Invalid credentials';
}
}
?>
<!-- 登录表单 -->
<form method="post">
<input type="text" name="username" required>
<input type="password" name="password" required>
<button type="submit">Login</button>
</form>
最佳实践
- 密码存储:始终使用
password_hash()(推荐PASSWORD_DEFAULT/PASSWORD_BCRYPT) - 会话安全:
session_regenerate_id(true)登录成功后刷新会话ID- 设置
session.cookie_httponly=1和session.cookie_secure=1
- 速率限制:记录失败次数,超过阈值锁定账户或延迟响应
常见错误
- 错误1:直接拼接SQL查询(导致SQL注入)
$sql = "SELECT * FROM users WHERE username='$username'"; - 错误2:使用md5/sha1存储密码
$hash = md5($password); // 极易被彩虹表破解 - 错误3:未刷新会话ID(会话固定漏洞)
- 错误4:未设置Cookie安全标志(可能被XSS窃取)
扩展知识
- 双因素认证:集成TOTP(如Google Authenticator)
- 密码策略:强制要求最小长度、特殊字符等
- 持续防护:
- 使用
password_needs_rehash()在算法升级时自动更新哈希 - 定期审计会话活动
- 使用
- 现代替代方案:考虑OAuth2/OpenID Connect集成第三方登录