2014-01-07 80 views
1

我正在開發一個php/laravel-4項目,我們需要自動對來自我們發送給他們的電子郵件中鏈接的用戶進行身份驗證,因此我們需要對鏈接進行時間限制,以便鏈接在電子郵件不會驗證過期時間過去後,我已經到了這種方法,但我對它的安全性有一些懷疑:通過電子郵件進行PHP用戶身份驗證

首先我使用用戶的電子郵件,時間戳和一個密鑰,如下所示做一個MD5散列:

$timestamp = time(); 
$hash = md5($email . $timestamp . $secret_key); 

然後我就可以產生這樣的網址:

$url = "http://www.example.com/url?email={$email}&hash={$hash}&timestamp={$timestamp} 

那麼我可以檢查時間戳(用於時間驗證)並重新生成散列並使用提供的電子郵件驗證用戶,您認爲它有任何安全漏洞嗎?如果是,請給我建議安全的方法。

+0

什麼是防止有人嗅探網絡流量,並在預期用戶之前使用此鏈接?假設很多用戶將通過未加密的方法檢查電子郵件是安全的。 –

+3

爲什麼包含時間戳?散列本身在理論上是唯一的,所以只發送**散列,並將關聯的用戶ID /時間戳存儲在數據庫表中。當用戶點擊鏈接時,您在表格中查找哈希值,檢查它是否仍然有效,並在該點獲取用戶ID。 –

+0

@JohnChrysostom所以你有什麼建議通過電子郵件驗證用戶? – Amir

回答

3

我不會這麼做。我會做什麼:

創建一個表爲您的鏈接:

public function up() 
{ 
    Schema::create('login', function($table) { 
     $table->string('id')->primary(); 

     $table->string('user_id'); 

     $table->timestamps(); 
    }); 
} 

你生成一個鏈接添加一行這個表中的每個時間:

$user = User::find(1); 

$login = Login::create(['id' => Login::generateID(), 'user_id' => $user->id]); 

$url = "http://www.example.com/url?login_id={$login->id}" 

然後當用戶點擊鏈接,你可以自動登錄他,也立即無效該鏈接:

$login = Login::findOrFail(Input::get('login_id')); 

$user = User::find($login->user_id); 

Auth::login($user); 

$login->delete(); 

並創建一個藝術ISAN命令在該表periodiacally刪除舊記錄:

Login::where('created_at', '<=', Carbon\Carbon::now()->subDays(2))->delete(); 

這可以爲generateID()的代碼,這是一個基本的UUID代碼生成:

public static function v4() 
{ 
    return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', 

    // 32 bits for "time_low" 
    mt_rand(0, 0xffff), mt_rand(0, 0xffff), 

    // 16 bits for "time_mid" 
    mt_rand(0, 0xffff), 

    // 16 bits for "time_hi_and_version", 
    // four most significant bits holds version number 4 
    mt_rand(0, 0x0fff) | 0x4000, 

    // 16 bits, 8 bits for "clk_seq_hi_res", 
    // 8 bits for "clk_seq_low", 
    // two most significant bits holds zero and one for variant DCE1.1 
    mt_rand(0, 0x3fff) | 0x8000, 

    // 48 bits for "node" 
    mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff) 
    ); 
} 

連接到系統上的任何這樣的字符串。

+0

爲什麼不只是使用隨機MD5散列? – Amir

+0

您應該在查找ID時檢查時間戳。如果由於某種原因在清理過程中存在漏洞,您可能會得到陳舊的結果。您也可以在檢查時運行清理程序,或者等待檢查時間的1/10。 – Halcyon

+0

我並沒有試圖給出一個完整的代碼實現,只是一個更好的方法的指南,如何真正實現它是由OP決定的。只是改變了v4的實現,你是對的。 –

0

只要密鑰不是用戶密碼,那麼這對我來說似乎很好。

0

你不會找到一個完全安全的方法來做到這一點。如果某人的電子郵件遭到黑客攻擊?或一百萬其他情況。

我認爲你最好的選擇是發送包含用戶名(或電子郵件)的電子郵件散列,並可能再次發送時間戳。一旦他們點擊鏈接,他們必須輸入密碼,然後繼續。

您也可以在電子郵件鏈接中包含重定向鏈接,以便腳本在輸入密碼後將其重定向到適當的位置。

1

md5不是密碼安全的,因爲它是容易破解(以密碼術語)。

主要關注的是,md5,你不希望出現這種情況,你希望它儘可能,它需要你太久生成和驗證慢,但不能這麼慢。

看看PHP password guide,這裏至關重要的是cost參數。更高的成本意味着它更安全。基本上,cost所做的是:它增加了散列函數應用的次數,更多的應用程序意味着它需要更長的時間來製作,因此蠻力。


你可以做的另一件事是混淆你的輸入。如果您可以將您的URL更改爲:

$string = $timestamp . "|" . $email . "|" . $hash; 
// then encrypt this string 
$encrypted = mcrypt_encrypt($cypher, $secret_password_2, $string); // or any other two-way encryption 
$url = $base . "?hash=" . $encrypted; 

當您收到散列解密後,將其拆分並檢查散列。這使得它不太明顯發生了什麼;所有3個值都打包在一個加密的blob中。

+0

這將以真正的長$加密字符串結束。 – Amir

+0

網址的事實上的限制是2000個字符,我們甚至沒有接近!也許100? – Halcyon

相關問題