2013-03-16 59 views
2

我有興趣在登錄頁面上編寫remember me功能,該功能將在個人計算機上記錄一個cookie,以保存多久。我知道這裏有危險,所以我想確保我以正確的方式做到這一點。爲「記住我」功能設置cookie的最安全的方法

我聽說過有人在數據庫表和cookie本身之間創建鏈接進行驗證;但是,不知道如何做到這一點,或者如果推薦。我對cookies不熟悉,所以請解釋一下可能的最佳方式。我沒有任何例子,因爲就像我說過的,我之前從未編寫過這個代碼,並且希望確保我以正確的方式做到這一點,並從完成它的人那裏獲得輸入。

我不確定Facebook的cookies是否永久存在,我只知道在我的電腦上,除非刪除我的歷史記錄,否則我永遠都不需要重新登錄。所以我可能想要像他們那樣做。

在此先感謝!

+0

你有什麼擔心? – 2013-03-16 21:00:01

+0

記住我的曲奇並沒有真正的魔力;設想一下,設想一下新建一個隨機密碼。將其存儲在數據庫中,並且每當用戶發送cookie時,都使用它來登錄它們,而不是真正的用戶名和密碼。當它到期時(每個cookie過期,有時候如果長時間不使用,有時在一年後,有時候當用戶明確註銷時),將其從數據庫中刪除。 – Dave 2013-03-16 21:00:04

回答

3

我還沒有爲自己的編碼這個,但我會接近這樣的問題:當用戶提出了一個cookie

創建可用於強制有效性檢查表持久性:

create table RememberMe 
(
    user_id int(10) NOT NULL, 
    user_token char(10) NOT NULL, 
    token_salt int(6) NOT NULL, 
    time  int(10) NOT NULL, 
    PRIMARY KEY (user_id), 
    CONSTRAINT nameYourConstraint 
       FOREIGN KEY (user_id) 
       REFERENCES userTableName (whatever_user_id_equals) 
) 

爲了填充這個表我的一些代碼行添加到登錄,在這個例子中我將使用僞代碼

// userID variable has been sanitized already so 
// check if user clicked remember me 
// and if the user logged in successfully: 
if (rememberMe == checked && login() == true) 
{ 
    // random number to serve as our key: 
    randomNumber = random(99, 999999 ); 

    // convert number to hexadecimal form: 
    token = toHex((randomNumber**randomNumber)); 

    // encrypt our token using SHA1 and the randomNumber as salt 
    key = encrypt(token, randomNumber, SHA1); 

    // get the number of seconds since unix epoch: 
    // (this will be 10 digits long until approx 2030) 
    timeNow = unix_time() 

    // check to see if user is in table already: 
    sql = "SELECT user_id FROM RememberMe 
      WHERE user_id = 'userID'"; 

    // connect to database: 
    db = new DBCon(); 

    result = db->query(sql); 

     // number of rows will always be 1 if user is in table: 
     if (result->rows != 1) 
      exists = true; 
     else 
      exists = false; 

    result->free_memory(); 

     if (exists == true) 
     { 
      sql = "UPDATE RememberMe SET 
        user_id = 'userID' 
        user_token = 'token' 
        token_salt = 'randomNumber' 
        time  = 'timeNow'"; 
     } 
     else 
     { 
      sql = "INSERT INTO RememberMe 
        VALUES('userID', 'token', 'randomNumber', 'timeNow')"; 
     } 

    result = db->query(sql); 

     // the affected rows will always be 1 on success 
     if (result->affected_rows != 1) 
     { 
      print("A problem occurred.\nPlease log in again."); 
      quit(); 
     } 

    result->free_memory(); 

    // create a new cookie named cookiemonster and store the key in it: 
    // (we're not actually storing a score or birthday, its a false flag) 
    set_cookie("CookieMonster", escape("score="+ userID +"birthday="+ key); 
} 

這段代碼所做的是檢查用戶是否已經檢查過記住我,並且它爲用戶填充了一個鍵,一個令牌和一個鹽以及一個時間(以便您可以對記憶執行時間限制我的特色)。

從這裏您可以將代碼添加到您的網站如果餅乾怪獸 Cookie設置,檢查和如果是你可以按照以下步驟來加強其有效性:

  1. 提取用戶ID和來自cookie的密鑰

  2. 用userID查詢數據庫以查看是否

    --> a) user has requested to be remembered 
    
        --> b) check the time to see if they cookie is still valid 
    
        --> c) extract the token and salt from database table record 
    
  3. 通過encrypt()函數調用運行令牌和salt,並與提供的密鑰 進行匹配。

  4. 如果一切正常,創建一個新的會話和用戶登錄。

現在每個用戶來到你的網站,他們也將登錄時間,並且在事件那他們的電腦遭到入侵攻擊者將無法訪問他們的密碼

邊注意:您應該始終要求您的用戶在更改密碼或電子郵件時提供密碼,這種方式應該是用戶的cookie找到錯誤的方式哈您的攻擊者將無法竊取該帳戶。

+0

我喜歡這個......我在你的登錄腳本中注意到,它所做的只是更新令牌和所有細節......它實際上並沒有檢查cookie是否存在......我有點困惑那。在檢查表和cookie之間是否正確以及所有表單和cookie之間是否正確後,是否應該在新的時間將細節更新爲新的數字後才能完成此操作?或者,我沒看到的是什麼? – kdjernigan 2013-03-17 02:14:28

+1

是的,抱歉,我知道它有點令人困惑,我只是想讓這個想法得到解決。我在那裏說(我想!)需要添加一些代碼來檢查cookie是否設置。這是所有僞代碼,以便它可以被移植到任何語言。但是,大多數函數都是基於PHP庫中的函數。 – 2013-03-17 03:31:28

+1

您網站上的所有頁面都應該檢查cookie,而不僅僅是一個頁面(任何可能是入口點的頁面,至少)。如果cookie已設置,請使用用戶標識並從數據庫中獲取信息。如果沒有,這個代碼會在用戶登錄時運行。假設你想讓'記住我'功能記住兩個星期的人[這是在你的代碼中指定的,通過在幾秒鐘內獲取當前時間並從中減去時間該cookie已設置。一旦你完成了減法,你可以比較結果與時間限制。] – 2013-03-17 03:32:09

2

這種策略被認爲是最佳的做法:看看這篇文章:http://jaspan.com/improved_persistent_login_cookie_best_practice

+0

我很欣賞這篇文章,它確定。給了我一些指點。我或多或少不確定如何編碼這個,但下面的人給了我一個如何編碼的例子。我可以在整體代碼概念上得到您的意見,並確保它是一個很好的代碼嗎? – kdjernigan 2013-03-17 02:17:03

3

一個持久的cookie的最佳方法我目前所看到的是Barry Jaspan's

  1. 當用戶成功登錄並記住我已選中,除了標準會話管理Cookie以外,還會發布登錄Cookie。
  2. 登錄cookie包含用戶的用戶名,系列標識符和令牌。該系列和令牌是從 一個適當的大空間不可猜測的隨機數。所有三個數據一起存儲在數據庫 表中。
  3. 當未登錄的用戶訪問該網站並顯示登錄Cookie時,會在數據庫中查找用戶名,系列和令牌。
    1. 如果三元組存在,則認爲用戶已通過認證。使用的令牌從數據庫中刪除。生成一個新的令牌, 存儲在數據庫中,使用用戶名和相同的系列標識符 ,並向用戶發佈包含全部三個的新登錄cookie。
    2. 如果用戶名和系列號存在但令牌不匹配,則認爲是盜用。用戶收到措辭強烈的警告 ,並且用戶的所有會話都被刪除。
    3. 如果用戶名和系列不存在,則會忽略登錄cookie。

我建議你閱讀整篇文章,上面是要點。

此外,您只希望通過SSL連接發出這些cookie,並在其上設置securehttponly標誌。

由於這意味着在連接到經由SSL服務器的用戶僅通過驗證,我還設置Strict-Transport-Security HTTP標頭強制瀏覽器在未來始終使用SSL和另外一個簡單的餅乾等persistent_login_available=yes用於非SSL連接。如果瀏覽器通過非SSL連接訪問站點,並且服務器看到persistent_login_available cookie,它會將訪問者重定向到SSL版本並通過安全cookie驗證用戶身份。

有了這個過程,你就可以儘可能地安全。它可以可能有點超過您的需求,但你決定。

+0

我欣賞這篇文章和它的def。給了我一些指點。我或多或少不確定如何編碼這個,但下面的人給了我一個如何編碼的例子。我可以在整體代碼概念上得到您的意見,並確保它是一個很好的代碼嗎? – kdjernigan 2013-03-17 02:16:32