PHP项目Cookie过期规则如何设计

wen PHP项目 20

本文目录导读:

PHP项目Cookie过期规则如何设计

  1. 核心概念:Cookie 的两种过期机制
  2. 设计原则与通用规则
  3. 常见场景的过期规则设计
  4. 高级设计:Token 轮换与吊销机制
  5. 过期时间的安全考量
  6. 完整的设置示例(现代 PHP 7.3+)
  7. 最佳实践一览表

设计 PHP 项目中的 Cookie 过期规则,核心是平衡安全性用户体验业务需求,以下是一套从基础到高级的完整设计指南。

核心概念:Cookie 的两种过期机制

  1. 会话 Cookie (Session Cookie):不设置 Expires 或 Max-Age 属性,浏览器关闭后自动删除。
  2. 持久 Cookie (Persistent Cookie):设置了 ExpiresMax-Age,在指定时间后删除。
// 设置会话 Cookie (浏览器关闭即失效)
setcookie('name', 'value');
// 设置持久 Cookie (30天后失效)
setcookie('name', 'value', time() + 86400 * 30);
// 或使用 Max-Age (更推荐, 相对时间)
setcookie('name', 'value', ['expires' => time() + 86400 * 30, 'samesite' => 'Lax']);
// 注意: PHP 7.3+ 推荐使用 options 数组形式

设计原则与通用规则

  1. 最小必要原则:Cookie 只存标识符(如 Session ID、Token),不存敏感数据(密码、证件号)。
  2. 安全优先:必须设置 HttpOnlySecureSameSite 属性。
  3. 区分业务场景:登录态、购物车、偏好设置、7天免登录等,过期时间应不同。

常见场景的过期规则设计

用户登录态(最核心)

  • 短期会话:会话 Cookie + Session 机制(默认)。

    • 优点:最安全,用户关闭浏览器即退出。
    • 缺点:体验差,频繁登录。
    • 代码session_start(); (PHP 默认使用会话 Cookie)。
  • 长期免登录(记住我):持久 Cookie + Token 刷新机制。

    • 设计要点
      • 使用随机 Token(非用户密码)存储在 Cookie 和数据库中。
      • 过期时间:建议 7-30天,一般不超过 30 天。
      • 刷新规则:每次有效请求时,重新生成 Token 并更新 Cookie 和数据库,防止固定 Token 被窃取后永久有效。
      • 安全处理:Cookie 中的 Token 应该被哈希后再存入数据库(不要存明文)。
    • 代码示例
// 1. 用户登录时勾选“记住我”
if ($rememberMe) {
    $token = bin2hex(random_bytes(32)); // 生成随机 Token
    $expires = time() + 86400 * 7; // 7天后过期
    // 存储到数据库 (用户ID, 哈希后的Token, 过期时间)
    $hashedToken = hash('sha256', $token);
    saveTokenToDatabase($userId, $hashedToken, $expires);
    // 设置 Cookie
    setcookie('remember_token', $token, [
        'expires' => $expires,
        'path' => '/',
        'domain' => 'example.com',
        'secure' => true,
        'httponly' => true,
        'samesite' => 'Lax'
    ]);
}
// 2. 用户下次访问时验证
if (!isset($_SESSION['user_id']) && isset($_COOKIE['remember_token'])) {
    $token = $_COOKIE['remember_token'];
    $hashedToken = hash('sha256', $token);
    // 从数据库查找匹配且未过期的 Token
    $userData = findTokenInDatabase($hashedToken);
    if ($userData && $userData['expires'] > time()) {
        // 重新登录会话
        $_SESSION['user_id'] = $userData['user_id'];
        // **关键: 刷新 Token** (防止固定 Token 泄露)
        rotateRememberMeToken($userData['user_id']);
    } else {
        // Token 无效或过期, 删除 Cookie
        setcookie('remember_token', '', time() - 3600);
    }
}

购物车(未登录状态)

  • 设计:持久 Cookie,过期时间灵活。
  • 推荐时间3-14天(避免用户在选商品过程中购物车丢失)。
  • 注意:购物车数据量可能很大,Cookie 有大小限制(4KB),可以用 Session 或数据库存储,Cookie 只存一个 Session ID。
// 存储购物车数据到 Session, 浏览器关闭即消失不合适
// 方案: 使用独立的购物车 Session ID 并设置持久 Cookie
$cartSessionId = session_create_id();
$expires = time() + 86400 * 7;
setcookie('cart_session_id', $cartSessionId, $expires, '/', '', true, true);

用户偏好设置(主题、语言、字体大小)

  • 设计:持久 Cookie,过期时间非常长(365天或更长)。
  • 安全性:不敏感,可以 HttpOnly = false(前端 JS 可读取,用于动态换肤),但建议还是 HttpOnly=true 并通过 API 读取。
  • 示例
setcookie('theme', 'dark', [
    'expires' => time() + 86400 * 365, // 一年
    'path' => '/',
    'samesite' => 'Lax'
]);

跟踪与分析(如 Google Analytics 的 _ga)

  • 设计:持久 Cookie,1-2 年。
  • 注意:需符合 GDPR/中国个人信息保护法,用户需同意。

高级设计:Token 轮换与吊销机制

这是防止 Cookie 被窃取后滥用(持久登录令牌)的关键。

  • 轮换机制
    • 每次使用“记住我” Token 成功验证后,立即生成新 Token(旧 Token 失效)。
    • 这样即使黑客窃取了某个 Token,用户下次正常登录后,旧 Token 自动失效。
  • 版本化
    • 数据库 Token 记录增加 version 字段,每次轮换版本号 +1,服务器只认最新版本号的 Token。
  • 吊销机制
    • 用户修改密码、注销其他设备、账户被锁定等操作时,删除/作废该用户所有遗忘 Token
    • 需要数据库支持:DELETE FROM user_tokens WHERE user_id = ?

过期时间的安全考量

  1. 敏感操作:支付、修改密码、绑定手机等操作不能只靠 Cookie 登录态,必须再次验证密码或 2FA。
  2. 会话超时
    • 空闲超时:用户长时间无操作(如 30 分钟),自动销毁 Session(短 Token)。
    • 绝对超时:用户从登录开始,最多会话 8 小时或 24 小时,强制重新登录(适用于银行、后台管理系统)。
    • 实现:在 Session 中存储 last_activitylogin_time,每次请求时检查。
// 会话空闲超时
if (isset($_SESSION['last_activity']) && (time() - $_SESSION['last_activity'] > 1800)) {
    session_destroy();
    session_start();
    // 重定向到登录页
}
$_SESSION['last_activity'] = time();
// 会话绝对超时
if (isset($_SESSION['login_time']) && (time() - $_SESSION['login_time'] > 28800)) { // 8小时
    // 强制注销
}

完整的设置示例(现代 PHP 7.3+)

// 设置一个安全的长久登录 Cookie
$cookieName = 'auth_token';
$cookieValue = bin2hex(random_bytes(32));
$expires = time() + 86400 * 14; // 14 天后过期
setcookie($cookieName, $cookieValue, [
    'expires'  => $expires,
    'path'     => '/',
    'domain'   => 'example.com', // 匹配你的域名
    'secure'   => true,          // 仅 HTTPS
    'httponly' => true,          // 禁止 JavaScript 访问
    'samesite' => 'Lax'          // 防止 CSRF, Lax 是较好的平衡
]);
// 删除 Cookie
setcookie($cookieName, '', [
    'expires' => time() - 3600,
    'path' => '/',
    'domain' => 'example.com',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Lax'
]);

最佳实践一览表

场景 类型 过期时间 安全属性 备注
登录会话 Session 浏览器关闭 HttpOnly, Secure, SameSite 默认行为,最安全
记住我 Persistent 7-30 天 HttpOnly, Secure, SameSiteToken 轮换 必须结合数据库 Token 存储和轮换
购物车 Persistent 3-14 天 HttpOnly, Secure 最好用 Session ID 控制,数据存服务端
偏好设置 Persistent 1 年 Secure, SameSite (可 HttpOnly=false 给前端使用) 安全性低,可灵活处理
分析跟踪 Persistent 1-2 年 Secure, SameSite 需用户同意
敏感操作令牌 一次性 5-15 分钟 HttpOnly, Secure, SameSite=Strict 用于支付、密码重置确认等,用完立即删除
CSRF Token Session 浏览器关闭 SameSite=Strict 放在表单隐藏字段,不通过 Cookie

最后建议:不要完全依赖 Cookie 过期时间来保证安全,配合服务端 Session 管理、IP 变化检测、异常登录行为报警等,构建多层防御体系。

抱歉,评论功能暂时关闭!