python保持登录状态_“保持登录状态”-最佳方法
小編典典
好的,讓我直言不諱:如果您為此目的將用戶數據或從用戶數據派生的任何內容放入cookie,則表示您做錯了。
那里。我說了。現在我們可以繼續實際的答案了。
您問哈希用戶數據有什么問題嗎?好吧,它可歸結為暴露表面和安全性。
想象一下您是攻擊者。您會在會話中看到為“記住我”設置的加密cookie。寬度為32個字符。嘖嘖。那可能是MD5 …
我們還要想象一下,他們知道您使用的算法。例如:
md5(salt+username+ip+salt)
現在,攻擊者所需要做的就是強行加“鹽”(這實際上不是鹽,但稍后會更多),他現在可以使用其IP地址的任何用戶名生成他想要的所有偽造令牌!但是強行撒鹽很難,對嗎?絕對。但是現代的GPU非常擅長于此。并且除非您在其中使用足夠的隨機性(使其足夠大),否則它將很快下降,并隨即成為城堡的關鍵。
簡而言之,唯一保護您的是鹽,它并沒有像您想的那樣真正保護您。
可是等等!
所有這些都假定攻擊者知道該算法!如果這是秘密且令人困惑,那么您就安全了,對嗎? 錯誤 。這種思路有一個名字:“ 通過模糊實現安全” ,
永遠不要 依賴它。
更好的方法
更好的方法是永遠不要讓用戶的信息離開服務器,除了ID。
用戶登錄時,生成一個大的(128至256位)隨機令牌。將其添加到將令牌映射到用戶標識的數據庫表中,然后將其發送到cookie中的客戶端。
如果攻擊者猜測另一個用戶的隨機令牌怎么辦?
好吧,讓我們在這里做一些數學運算。我們正在生成一個128位隨機令牌。這意味著有:
possibilities = 2^128
possibilities = 3.4 * 10^38
現在,為了展示這個數字有多么荒謬,讓我們想象一下互聯網上的每臺服務器(今天的數字是5000萬)試圖以每秒10億的速度暴力破解該數字。實際上,您的服務器會在這樣的負載下融化,但讓我們來解決這個問題。
guesses_per_second = servers * guesses
guesses_per_second = 50,000,000 * 1,000,000,000
guesses_per_second = 50,000,000,000,000,000
因此,每秒50萬億次猜測。快!對?
time_to_guess = possibilities / guesses_per_second
time_to_guess = 3.4e38 / 50,000,000,000,000,000
time_to_guess = 6,800,000,000,000,000,000,000
6.8秒
讓我們嘗試將其歸結為更友好的數字。
215,626,585,489,599 years
甚至更好:
47917 times the age of the universe
是的,這是宇宙年齡的47917倍…
基本上,它不會被破解。
所以總結一下:
我建議的更好的方法是將cookie分為三個部分存儲。
function onLogin($user) {
$token = GenerateRandomToken(); // generate a token, should be 128 - 256 bit
storeTokenForUser($user, $token);
$cookie = $user . ':' . $token;
$mac = hash_hmac('sha256', $cookie, SECRET_KEY);
$cookie .= ':' . $mac;
setcookie('rememberme', $cookie);
}
然后,進行驗證:
function rememberMe() {
$cookie = isset($_COOKIE['rememberme']) ? $_COOKIE['rememberme'] : '';
if ($cookie) {
list ($user, $token, $mac) = explode(':', $cookie);
if (!hash_equals(hash_hmac('sha256', $user . ':' . $token, SECRET_KEY), $mac)) {
return false;
}
$usertoken = fetchTokenByUserName($user);
if (hash_equals($usertoken, $token)) {
logUserIn($user);
}
}
}
注意:不要使用令牌或用戶和令牌的組合來查找數據庫中的記錄。始終確保根據用戶來獲取記錄,并使用時序安全比較功能隨后對獲取的令牌進行比較。有關定時攻擊的更多信息。
現在, 非常
重要的一點是SECRET_KEY成為一個密碼秘密(由類似東西的東西生成/dev/urandom和/或從高熵輸入中得出)。另外,還GenerateRandomToken()需要成為一個強大的隨機源(mt_rand()還不夠強大。請使用一個庫,例如RandomLib或random_compat,或mcrypt_create_iv()與一起使用DEV_URANDOM)…
這hash_equals()是為了防止定時攻擊。如果使用PHP
5.6以下的PHP版本,hash_equals()則不支持該功能。在這種情況下,您可以替換hash_equals()為timingSafeCompare函數:
/**
* A timing safe equals comparison
*
* To prevent leaking length information, it is important
* that user input is always used as the second parameter.
*
* @param string $safe The internal (safe) value to be checked
* @param string $user The user submitted (unsafe) value
*
* @return boolean True if the two strings are identical.
*/
function timingSafeCompare($safe, $user) {
if (function_exists('hash_equals')) {
return hash_equals($safe, $user); // PHP 5.6
}
// Prevent issues if string length is 0
$safe .= chr(0);
$user .= chr(0);
// mbstring.func_overload can make strlen() return invalid numbers
// when operating on raw binary strings; force an 8bit charset here:
if (function_exists('mb_strlen')) {
$safeLen = mb_strlen($safe, '8bit');
$userLen = mb_strlen($user, '8bit');
} else {
$safeLen = strlen($safe);
$userLen = strlen($user);
}
// Set the result to the difference between the lengths
$result = $safeLen - $userLen;
// Note that we ALWAYS iterate over the user-supplied length
// This is to prevent leaking length information
for ($i = 0; $i < $userLen; $i++) {
// Using % here is a trick to prevent notices
// It's safe, since if the lengths are different
// $result is already non-0
$result |= (ord($safe[$i % $safeLen]) ^ ord($user[$i]));
}
// They are only identical strings if $result is exactly 0...
return $result === 0;
}
2020-05-26
總結
以上是生活随笔為你收集整理的python保持登录状态_“保持登录状态”-最佳方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python调用ffmpeg_Pytho
- 下一篇: python多线程实现同步的方式_深入解