我想知道 cookie 登录最安全的方式是什么?如果您只是将通行证(用盐加密)和用户名存储在 cookie 中并针对用户表进行验证,则潜在的攻击者可以窃取 cookie 并登录。人们通常不会在那里查看“最后一次在线”。
那么“记住我的饼干”有更好的方法吗?IP不是一个好的选择,是吗?(有些机器一直在改变IP)。
我想我找到了一个聪明的解决方案!
这个(复杂的?)脚本的优点:
我在数据库中创建了一个包含以下信息的表:
session | token | username | expire
记住我的 cookie 将具有以下设置:
$value = "$session|$token|$userhash"; //Total length = 106
Session将是一个 40 (sha1) 个字符的字符串。Token将是一个 32 (md5) 个字符的字符串。Userhash在 cookie 中将是 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
}
脚本的优点:
参考:http: //jaspan.com/improved_persistent_login_cookie_best_practice
这种“记住我”功能始终是一个额外的安全风险。
因为就像在会话中一样,您只有一个标识符,不仅足以识别用户(它是谁?),而且还可以验证该用户(真的是他/她吗?)而无需进行实际验证。
但与具有(或应该具有)只有很短的生命时间(通常少于一个小时)的会话相反,并且标识符是(或应该)定期更改(基于时间并根据真实性/权威状态更改的必要性) ,“记住我”标识符的有效期为数天,甚至数月或数年!而这种长有效期带来了额外的安全风险。
因此,在询问如何实现这样的“记住我”功能之前,您应该问自己是否真的想要额外的安全风险。这主要取决于您的应用程序拥有的资产和身份验证的目的,以及您是否想冒“记住我”功能所带来的假冒/身份盗窃的风险。
如果是这样,请确保使用 HTTPS 提供基本安全性,并在 cookie 中设置HTTPOnly标志和安全标志。然后您可以执行以下操作来构建这样的“记住我”功能:
身份验证请求
如果用户通过 HTTPS 进行身份验证并设置了“记住我”选项,则生成一个随机的记住我令牌,将其存储在服务器端的“记住我”数据库中,并设置带有安全标志的记住我cookie价值。然后开始一个新会话并设置一个记住我的标志。
任何其他要求
有了这个,身份验证通过 HTTPS 得到保护,包括初始身份验证和“记住我”身份验证。并且用户仅在当前会话期间是真实的;如果过期,用户必须通过使用记住我令牌或提供他/她的登录凭据来重新进行身份验证。并且由于记住我令牌存储在数据库中,用户可以使任何现有的记住我令牌无效。
最受欢迎的方式:
许多脚本使用某种会话跟踪。当用户第一次访问网站时,它会为用户生成一个唯一的随机 ID,并将会话信息存储在服务器中,并将 ID 存储在 cookie 中。然后,服务器使用唯一 ID(称为会话 ID)来识别用户。与会话 ID 关联的信息只有服务器才能看到。PHP默认使用这个,
有些将用户数据存储在 cookie 本身中,但带有使用秘密字符串作为密钥的 HMAC 签名。如果签名不匹配,脚本会丢弃 cookie。这样,服务器就不必将会话数据保存在服务器上。用户通过查看 cookie 来查看会话中的内容,因此您不应在其中存储敏感数据。只需用户 ID(可能还有登录时间和 cookie 到期时间)就足够了。虽然用户可以看到会话信息中的内容,但 cookie 中的签名确保用户无法自己修改会话数据。
这些方式提供了一些安全性,即用户不能篡改会话数据,但不能保护用户免受窃听。他们总是可以使用数据包嗅探器并从任何开放的 WiFi 网络中窃取会话。一些应用程序确实依赖于用户 IP,但攻击者是否在同一个网络中并不重要。一些应用依赖User-Agent,但是当用户更新浏览器或从另一个浏览器导入数据时会出现问题。
如果您真的关心安全性,请使用 HTTPS。
另请阅读这篇文章,尤其是名为“网站运营商如何解决问题? ”的部分。