2016-10-04 151 views
2

我生成一個由單個使用令牌組成的url,並通過電子郵件將其發送給用戶。用戶應該點擊這個鏈接並重定向到一個頁面,該頁面將驗證令牌並執行一些操作。存儲的鹽漬令牌和令牌比較

在數據庫方面,我存儲了這個令牌(出於安全原因散列和醃製)。問題是我在驗證令牌時遇到了一些困難,因爲我存儲它的方式不能爲同一標記生成相同的鹽。因此,我無法將這種鹽與我儲存的鹽進行比較。

# Retrieving or creating object usertokens 
usr, created = UserToken.objects.get_or_create(email=email) 
# Adding a new token 
token = uuid.uuid4().hex 
usr.token = make_password(token) # Stores in the local database the salted and hashed token 
usr.save() 

我使用的這個make_password方法定義在django.contrib.auth.hashers中。

通過使用這種方法,我不能從相同的標記生成兩次相同的鹽。

>>> token = 'test' 
>>> enc_token1 = make_password(token) 
>>> enc_token2 = make_password(token) 
>>> enc_token1 == enc_token2 
False 

但是,這並不能幫助我從我的數據庫檢索對應於令牌的條目,我無法驗證它。

+0

現在有件事我從來沒有聽說過; _帶有鹽漬的標記_。你想用這些令牌來番茄醬嗎?...... –

+2

除了所有的笑話外,散列和醃製的目的是不能從散列字符串中獲取原始密碼。由於密碼經常以某種方式重用,並且希望密碼在潛在違規後很長時間內保持祕密,所以需要密碼。令牌可以簡單地重置,然後攻擊者絕對不會使用獲取的令牌。正如您已經注意到的,沒有有效的方法來查詢鹽漬和散列的標記。這就是爲什麼令牌通常以純文本格式存儲的原因。爲了什麼特定的安全原因,你想存儲他們散列? – knbk

回答

1

使用一個簡單的字符串相等性檢查兩個哈希和鹽漬標記將不起作用。該Django docs for password managementdjango.contrib.auth.hashers命名空間來處理這一切爲你提供了一個非常簡單的方法:

>>> token = 'test' 
>>> enc_token1 = make_password(token) 
>>> check_password('test', enc_token1) 
True 

check_password方法做了幾件事情篷子後面,像檢查,如果哈希算法發生了變化。它返回實現BasePasswordHasher基類的算法的verify方法的結果。下面是來自source of the PBKDF2PasswordHasher實現的例子:

def verify(self, password, encoded): 
    algorithm, iterations, salt, hash = encoded.split('$', 3) 
    assert algorithm == self.algorithm 
    encoded_2 = self.encode(password, salt, int(iterations)) 
    return constant_time_compare(encoded, encoded_2) 

注意如何鹽被分割在「$」的encoded_string發現,由於Django docs note

一個用戶對象的密碼屬性在這種格式的字符串:

<algorithm>$<iterations>$<salt>$<hash> 
+0

感謝您的回答。使用check_password的問題是因爲我必須知道編碼的字符串和令牌。在我的情況下,我的輸入是令牌,我在我的數據庫中存儲了許多編碼的字符串。請原諒我,如果我錯了,但是,如果我使用check_password方法,似乎我應該執行令牌和所有存儲的編碼字符串之間的配對比較。也許這將是昂貴的。 – revy

+0

請記住,散列算法的本質是單向的。如果您在不知道原始字符串的情況下驗證哈希值,那麼您幾乎可以在第一位擊敗哈希的目的,這是爲了防止具有哈希值的攻擊者知道純文本。 – brianpck