使用登录cookie的相对安全的方法是什么?

时间:2011-01-23 11:45:57

标签: php cookies autologin

我想知道最安全的cookie登录方式是什么? 如果您只是将通行证(用盐加密)和用户名存储在cookie中 并根据用户表验证它,潜在的攻击者可以窃取cookie并登录。 人们通常不会在网上查看“最后一次”。

那么'记住我的饼干'有更好的方法吗? IP不是一个好选择,是吗? (有些机器一直在改变IP。)

3 个答案:

答案 0 :(得分:19)

我想我找到了一个聪明的解决方案!

这个(复杂的?)脚本的优点:

  • 用户成功登录后 与记住我检查,登录 cookie除了发布之外 标准会话管理 cookie中。[2]
  • 登录cookie包含用户的用户名,系列标识符和令牌。系列和令牌是来自适当大空间的不可取的随机数。这三个都存储在一个数据库表中。
  • 当未登录的用户访问该站点并显示登录cookie时,将在数据库中查找用户名,系列和令牌。
  • 如果存在三元组,则为用户 被认为是经过验证的。使用过的 令牌已从数据库中删除。一个 生成新令牌,存储在 用户名和数据库的数据库 相同的系列标识符和新的 包含所有三个的登录cookie是 发给用户。
  • 如果用户名和系列是 目前但令牌不匹配, 假设是盗窃。用户收到 一个措辞强烈的警告和所有 用户记住的会话是 删除。
  • 如果用户名和系列不是 目前,登录cookie被忽略。

我在数据库中创建了一个包含以下信息的表:

    session | token | username | expire

记住我的cookie会有这样的设置:

    $value = "$session|$token|$userhash"; //Total length = 106
  • Session将是一个40(sha1)的字符串 字符。
  • Token将是一个32(md5)的字符串 字符。
  • Cookie中的
  • Userhash将是一个 字符串32(用户名的md5) 字符。
  • 数据库中的
  • Username将是 普通用户名。
  • Expire现在将是+ 60天。

剧本:

if(isset($_SESSION['check']) || $_SESSION['check']){
    //User is logged in
}else if(isset($_COOKIE['remember']) && strlen($_COOKIE['remember'])==106){
    //THERE is a cookie, which is the right length 40session+32token+32user+2'|'
    //Now lets go check it...
    conncectdb(); //Sets connection
    //How do I protect this script form harmful user input?
    $plode = explode('|',$_COOKIE['remember']);
    $session = mysql_real_escape_string($plode[0]);
    $token = mysql_real_escape_string($plode[1]);
    $userhash = mysql_real_escape_string($plode[2]);
    $result = mysql_query(" SELECT user 
                FROM tokens 
                WHERE session = '$session' 
                AND token = '$token'
                AND md5(user) = '$userhash';")
    if(mysql_num_rows($result)==1){
        //COOKIE is completely valid!
        //Make a new cookie with the same session and another token.
        $newusername = mysql_result($result,0,0);
        $newsession = $session;
        $newtoken = md5(uniqid(rand(), true));
        $newuserhash = md5($username);
        $value = "$newsession|$newtoken|$newuserhash";
        $expire = time()+4184000;
        setcookie('remember', $value, $expire, '/', 'www.example.com', isset($_SERVER["HTTPS"]), true);
        mysql_query("   UPDATE tokens 
                SET token='$newtoken', expire='$expire'
                WHERE session = '$session' 
                AND token = '$token'
                AND md5(user)='$userhash';");
        //Set-up the whole session (with user details from database) etc...
    } else if(mysql_num_rows(mysql_query("SELECT user FROM tokens WHERE session = '$session' AND md5(user) = '$userhash';"))==1)){
        //TOKEN is different, session is valid
        //This user is probably under attack
        //Put up a warning, and let the user re-validate (login)
        //Remove the whole session (also the other sessions from this user?)
    } else {
        //Cookie expired in database? Unlikely...
        //Invalid in what way?
    }
} else {
    //No cookie, rest of the script
}

脚本的优点:

  • 多次登录。你可以创建新的 您正在使用的每台计算机的会话。
  • Cookie和数据库将保持清洁。 活跃用户每次更新cookie 登录。
  • 开头的会话检查 确保数据库不会 得到无用的请求。
  • 如果攻击者窃取了cookie,那就是 得到一个新的令牌,但不是新的 会话。所以当真正的用户访问时 旧网站(无效) 令牌但具有有效的用户会话 组合用户收到警告 潜在的盗窃。后 通过登录新的重新验证 会话已创建并且会话已创建 攻击者持有无效。该 重新验证确保受害者 真的是受害者,而不是受害者 攻击者。

参考:http://jaspan.com/improved_persistent_login_cookie_best_practice

答案 1 :(得分:6)

这样的“记住我”功能总是会带来额外的安全风险。

因为就像在会话中一样,你只有一个标识符,不仅可以识别用户(是谁?),而且还可以验证该用户(它真的是他/她?)没有进行实际身份验证。

但与具有(或应该)短寿命(大多数不到一小时)的会话相反,并且标识符(或应该)定期更改(由于真实性/权限而基于时间和必要性)状态变化),“记住我”标识符有效期为几天甚至数月甚至数年!这个漫长的有效期会带来额外的安全风险。

因此,在询问如何实现这样一个“记住我”功能之前,您应该问问自己是否真的需要额外的安全风险。这主要取决于您的应用程序具有的资产以及身份验证的目的,以及您是否希望冒“模仿我”功能所带来的冒充/身份盗窃的风险。

如果是这样,请确保使用HTTPS提供基本安全性并设置 HTTPOnly 标志和secure flag in your cookies。然后你可以做以下事情来构建这样一个“记住我”的功能:

  • 身份验证请求
    如果用户通过HTTPS进行身份验证并设置“记住我”选项,则生成随机记住我令牌,将其存储在服务器端的“记住我”数据库中,并设置记住我带有 secure 标志的cookie,带有该值。然后开始一个新会话并设置记住我标志。

  • 任何其他请求

    1. 如果没有当前会话,请通过HTTPS重定向到记住我页面,检查是否有记住我 cookie。如果有一个记住我令牌并且它是有效的,则使其无效,生成一个新令牌,将其存储在“记住我”数据库中,使用该新令牌设置cookie并创建一个新会话记住我标志集。否则重定向到登录页面。
    2. 如果当前会话无效(请务必使用strict session invalidation),如果记住我标志,则通过HTTPS重定向到记住我页面组;否则重定向到登录页面。

通过这种方式,身份验证通过HTTPS保护,包括初始身份验证和“记住我”身份验证。并且用户在当前会话期间仅是可信的;如果它到期,用户必须使用记住我令牌或提供他/她的登录凭据重新进行身份验证。当记住我令牌存储在数据库中时,用户可以使任何现有的记住我令牌无效。

答案 2 :(得分:4)

最受欢迎的方式:

  • 许多脚本使用某种会话跟踪。当用户首次访问网站时,它会为用户生成唯一的随机ID,在服务器中存储会话信息,并在cookie中存储ID 。然后,服务器使用唯一ID(称为会话ID)识别用户。 只有服务器才能看到与会话ID相关的信息。 PHP默认使用它,

  • 有些人将用户数据存储在cookie本身中,但使用密钥字符串作为密钥使用HMAC签名。如果签名不匹配,脚本会丢弃cookie。这样,服务器不必将会话数据保留在服务器上。用户通过查看cookie来查看会话中的内容,因此您不应将敏感数据存储在其中。只需用户ID(以及可能的登录时间和cookie到期时间)就足够了。 虽然用户可以看到会话信息中的内容,但Cookie中的签名可确保用户无法自行修改会话数据。

这些方式提供了一些安全性,用户无法篡改会话数据,但它不能保护用户免受窃听者的攻击。他们总是可以使用数据包嗅探器并从任何开放的WiFi网络窃取会话。有些应用程序确实依赖于用户IP,但攻击者是否在同一网络中并不重要。有些应用程序依赖于User-Agent,但是当用户更新浏览器或从其他浏览器导入数据时会出现问题。

如果您真的关心安全性,那么use HTTPS

另请阅读this article,尤其是网站运营商如何解决问题?

相关问题