2017-01-02 16 views
2

所以我想要一種方法來生成一個身份驗證令牌傳回給客戶端,以便它可以使用它來傳遞每個請求。生成完全唯一的令牌,從未使用過使用php

但是,生成以前從未使用的唯一令牌的最佳做法是什麼?

我需要保證唯一性,所以我不能完全將其基於php uniqid(),因爲兩個用戶完全同時登錄的可能性很小(機會很小但不能接受該機會)。

爲他們的用戶名前綴一個uniqid()值是不好的做法嗎?

此外,uniqid()的時間戳是基於易受重複值時鐘回退/轉發?

回答

0

很多歸結爲代碼可以變得多久,你需要它是多麼獨特,需要多大的難以預測,以及如果你有一個有效的代碼列表。

長度

第一關:簡單的數學意味着,如果你必須要能夠產生特有獨特的隨機字符串無限多的,你不能限制表示字符串的長度(這會變得無限......)。

如果必須將使用的值存儲在數據庫中,通常需要一個最大長度。

無論如何,無限長的字符串都會產生很多危險。

有多獨特?

顯然,使用時間並不是非常獨特,但您可以添加事物來減少碰撞的可能性,同時使其更難預測。

如果您有(當前)有效代碼的列表,則可以始終根據現有數據庫驗證生成的代碼,並在發生與當前有效代碼的衝突時重新生成新代碼。

顯然,一個簡單的日益增長的計數器將保證唯一性,但因爲它不是長度有限,這不是很方便,非常可預測等

很難預測

可能被猜到通常驗證碼是可怕的安全理念。所以你需要爲此辯護。

結合這一切

要結合這一切,你可以創建一個字符串的串聯:

  • 固定的,而是祕密的字符串(使它長)認爲這是一個密碼,該密碼讓猜你輸入極硬
  • 客戶端的IP地址
  • 客戶端
  • 蒂姆使用
  • 端口號Ë&日期
  • 僞隨機數
  • 客戶端用來標識自己
  • 用戶名
  • 串...

你不需要採取一切,訂單等。完全取決於你。多多益善。

一旦你有了這個字符串,你就選擇了一個散列函數,散列輸出的時間越長,碰撞的可能性就越小,但是代碼將在你的數據庫中使用更多的存儲空間。

現在的好選擇是sha-1或sha-256(md5有點太破碎了,不適用於任何新的東西)。

這爲您提供了一個固定長度的代碼,即使您在輸入中更改了一位,幾乎不可能預測攻擊者,並且導致衝突的可能性很小,代碼也會顯着變化。

有多小?這是非常不可能的,看到這裏的數學:https://crypto.stackexchange.com/questions/24732/probability-of-sha256-collisions-for-certain-amount-of-hashed-values

如果您需要完全排除這種可能性,並且不允許無限長的代碼,您只能檢查它使用的代碼,如果它被發現,你可以產生一個新的。

TL; DR

您可以添加其他的東西留出時間,例如連接遠程端的IP地址,僞隨機數,進程ID,你保密的固定字符串等等。 sha-256,而且你的固定長度很難預測代碼。

存在衝突的風險,但如果您給予足夠的輸入以消除衝突,則風險非常小:請檢查使用代碼列表。

+0

這真的很有幫助!謝謝:) – Michael

+0

一直在想這個多一點,最後一個問題。我希望該令牌被保證對該用戶是唯一的,將用戶標識(不是用戶名,而是唯一的自動增量int)添加到令牌的末尾是不好的做法,這將保證令牌永遠不會被不同的用戶。只是有點謹慎,如果令牌被刷新,但不會傳遞到客戶端應用程序正確,該客戶端,然後再次嘗試連接,但(它超薄的機會發生),其他客戶端用戶已經刷新自己的令牌,並因爲沒有按令牌在db中不再存在.... – Michael

+0

.....,這個新客戶端在off機會時被賦予了相同的標記值,但是沒有得到刷新標記的客戶端應用程序嘗試再次連接並且因爲該客戶端現在具有相同的標記,因爲此其他用戶現在可以訪問此其他用戶帳戶,但機會渺茫,但我需要盡一切努力防止任何潛在的未經授權的訪問。希望這是明確的 – Michael

0

我想你已經有一個數據庫存儲這些令牌,以便你可以檢查它是否是正確的。如果是這樣,你可以按你喜歡的方式生成令牌(即uniqid(),隨機字符串,......你喜歡的任何一種),並檢查數據庫中是否已經存在。如果不存在,您可以隨身攜帶,否則您可以生成新的並再次進行檢查。

+0

想到了這一點,但會對數據庫造成更多的壓力,每次生成新令牌時都會對可能的1百萬用戶進行檢查。但是,如果我無法找到一種將時間戳標記爲基礎的方法以及一個獨特的值,例如,這是我的後退解決方案。用戶名。 – Michael

+0

將用戶名追加或預先添加到時間戳應該可以工作,也許你甚至可以對它進行哈希以便它不易讀。 –

+0

我想如果我散列它雖然它可能更容易受到衝突,但使用時間戳和用戶名的值更獨特,但我不特別想發送用戶名 – Michael

-3

此方法適用於我......

$token = md5(date['u']); 

用途的秒數從紀元(1970年1月1日),所以幾乎你得到一個獨特的一個時間值的保證。 MD5將其轉換爲32個字符的字符串。 2個相同值的概率仍然不是非常小,但非常接近零。

使用日期w /'u'參數不會是由於DST引起的問題。

+0

首先,這不能保證提供唯一的ID,因爲它不僅可能,但實際上很可能兩個或更多(也許更多! )用戶將在一秒鐘內登錄,這將生成相同的標記。其次,理論上可能(儘管不太可能)兩個*不同*日期將會發生以產生相同的MD5總和。 – Kjartan

0

您可以使用UUID,通用唯一標識符。規格爲rfc4122

的摘錄:

其中一個主要的原因,使用UUID是沒有集中 權限需要對其進行管理(儘管格式使用 IEEE 802節點標識,有的則沒有)。因此,按需生成 可以完全自動化,並用於各種各樣的目的。如果需要 ,則此處描述的UUID生成算法支持每臺機器高達1000萬次每秒的高分配率,以便它們甚至可以用作事務ID。

UUID發電機

有各種語言的UUID發電機,只需確保實現使用在RFC-4122規範的算法。它們中的很多會簡單地爲UUID的每個十六進制字節使用一個隨機數,這將導致衝突。

+0

謝謝,任何PHP示例庫? – Michael

+0

您可以使用uniqid功能。 http://php.net/manual/en/function.uniqid.php。它基於當前時間生成一個唯一的字符串,以微秒爲單位 –