【问题标题】:Is my simple user authentication system secure enough?我的简单用户认证系统是否足够安全?
【发布时间】:2026-02-23 05:50:01
【问题描述】:

我一直在研究这个用于用户登录的身份验证系统,希望得到一些反馈。

我的想法是这样的。使用会话和一个额外的 cookie。会话 cookie 和附加 cookie 一起工作。在我的 Login 类中,检查用户名和密码是否正确后,我调用 sessionStart 方法并从数据库发送用户 ID:

public function sessionStart($id) {
    session_start();
    $cookieName = "RagingBull";
    $hash = $this->loginHash($id);
    setcookie($cookieName, $hash);
}

在我的 sessionStart 方法中,调用了一个 loginHash 方法。 loginHash 方法创建哈希并将会话 cookie 和附加 cookie 链接在一起。

public function loginHash($id) {
    $timeStamp              = time();
    $randNumber             = mt_rand(0, 1000);
    $userId                 = $id;
    $_SESSION['timeStamp']  = $timeStamp;
    $_SESSION['randNumber'] = $randNumber;
    $_SESSION['userId']     = $id;
    $userAgent              = $_SERVER['HTTP_USER_AGENT'];
    $salt                   = "On the Waterfront";
    $ipFrag                 = substr($this->getUserIP(), 0, 5);
    $forHash                = $timeStamp.$salt.$userId.$ipFrag.$randNumber.$userAgent;
    $hash                   = md5($forHash);
    return $hash;

}

为了创建哈希值,我使用

  • timeStamp,也保存在会话cookie中
  • randNumber,保存在会话cookie中
  • userId,保存在会话cookie中
  • 用户代理,
  • salt,保存在服务器内部
  • ipFrag,只是用户IP地址的一个片段。

我在会话 cookie 中保存了一些值,以便稍后在创建哈希值进行比较时使用它们。之后,我们回到 sessionStart 方法,并使用返回的哈希值创建额外的 cookie,然后用户登录。

对于身份验证,我有 Session 类。

class Session {

public function __construct() {

    session_start();
    // checks to see if all the cookies are there
    if(!isset($_SESSION['userId']) || !isset($_COOKIE['RagingBull'])) {
        header("Location:http://localhost/login.php");
    }

    //create hash for comparison
    $hash = $this->loginHash();

    //if hashes are not the same, redirect
    if(strcmp($hash, $_COOKIE['RagingBull']) !== 0) {
        header("Location:http://localhost/login.php");
    }
}

public function loginHash() {
    $timeStamp  = $_SESSION['timeStamp'];
    $randNumber = $_SESSION['randNumber'];
    $userId         = $_SESSION['userId'];
    $userAgent  = $_SERVER['HTTP_USER_AGENT'];
    $salt       = "On the Waterfront";
    $ipFrag     = substr($this->getUserIP(), 0, 5);
    $forHash    =  $timeStamp.$salt.$userId.$ipFrag.$randNumber.$userAgent;
    $hash       = md5($forHash);
    return $hash;
}

public function getUserIP() {
    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        $ip = $_SERVER['HTTP_CLIENT_IP'];
    } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    } else {
        $ip = $_SERVER['REMOTE_ADDR'];
    }

    return $ip;
}

}

要使用它,我只需创建 Session 类的实例。然后,在构造函数中,在基本检查之后,创建哈希进行比较,我使用之前保存的会话 cookie 中的 timeStamp、userId 和 randNumber,并将它们与请求页面的用户的用户代理和 ip 片段结合起来。

  • 是否存在明显的安全或逻辑缺陷?
  • 是否足够安全?
  • 对于每个页面请求,服务器是否有太多工作要做?
  • 这些都是不必要的吗?

【问题讨论】:

  • 请不要自己滚动密码散列,特别是不使用 MD5()。 PHP 提供password_hash()password_verify() 请使用它们。这里有一些good ideas about passwords如果你使用的是5.5之前的PHP版本there is a compatibility pack available here
  • 回答您的问题:1) 是的。 2) 没有 3) 大部分是不必要的 4) 是的
  • 我能做到。在将密码存储在数据库中并检查它们时,我使用了 password_hash() 和 password_verify()。但我在这里只使用了 md5,因为它不是关于密码,而是关于登录后身份验证的哈希。
  • Surley 用户登录后,您知道他们已通过身份验证,因为您在他们的会话中有帐户参考
  • @RiggsFolly ,好吧,你有时间再解释一下吗?我真的很感激。我认为通过这种方式,攻击者通过暴力攻击简单地猜测有效的会话会话密钥和额外的 cookie 密钥会有点困难。当然,我会重新生成会话 ID 和 cookie 密钥以防止会话固定。

标签: php security session authentication cookies


【解决方案1】:

这段代码做了很多不安全的无意义的事情。

  • 使用mt_rand() 代替random_int()
  • 使用md5($var) 代替hash('sha256', $var)
  • 使用md5($password) 代替password_hash()password_verify()
  • “登录哈希”完全没有意义。

如果您尝试进行持久身份验证(即“记住我”cookie),just implement that

如果您想防止会话攻击,只需使用 TLS(如果您仍在使用 PHP 5,请确保您的会话 ID 是从 /dev/urandom 生成的)和严格模式。每当用户登录或注销时,请致电session_regenerate_id(true)。完成。

这里的散列没有增加任何价值,而且您使用的工具并非用于安全身份验证。

【讨论】: