2017-07-24 33 views
0

我在我的RESTful API項目中使用身份驗證方法,我非常喜歡生成HMAC-SHA256簽名作爲身份驗證方法的想法。使用散列「密碼」生成HMAC簽名

客戶端被創建具有幾個簡單的步驟的簽名:

# example client-side code 
sig = hmac.new(bytes('SUPER_SECRET_KEY', 'utf-8'), b'', sha256) 
sig.update(request_path) 
sig.update(request_body) 
# ...other variables needed for generating the signature... 

signature = sig.hexdigest() 

和增加它與他的「用戶名」沿着請求報頭(例如Authorization: THE_USER_NAME:abcd1234xyz890)。

在服務器端,我想以同樣的方式重新創建它:

# example server-side code 
def do_check(request): 
    # get user name from request header 
    username = request.headers['Authorization'].split(':')[0] 

    # some method to retrieve the "secret key" from database 
    user = db.User().filter(username=username).one() 

    # use user's "secret key" to generate the signature 
    sig = hmac.new(bytes(user.key, 'utf8'), b'', sha256) 
    sig.update(bytes(request.path, 'utf-8')) 
    sig.update(request.data) 
    # ...other variables needed for generating the signature... 

    return sig.hexdigest() 
    # compare the returned signature with the one client sent us... 

這一切,只要我保存用戶的明文重點工作正常在我的數據庫:

| username  | key    | 
------------------------------------ 
| THE_USER_NAME | SUPER_SECRET_KEY | 

我們都知道,這是絕對不能接受的,所以我想簡單地散列SUPER_SECRET_KEYbcrypt和存儲散列串inste廣告:

| username  | key               | 
-------------------------------------------------------------------------------- 
| THE_USER_NAME | $2b$12$UOIKEBFBedbcYFhbXBclJOZIEgSGaFmeZYhQtaE4l6WobFW1qvIf6 | 

我現在面臨的問題是「密鑰」的客戶端使用的未哈希版本生成對此我不能做服務器端,因爲我沒有它簽名用純文本了。

其中一個類似方法的例子是generating HMAC signature in Amazon Web Services(也是simplified explanation of the same process),它不需要任何額外的登錄或認證,也沒有爲密鑰/祕密組合提供任何令牌或「替換」。我真的懷疑AWS是否在數據庫中以純文本形式存儲祕密(?)

如何在服務器端使用數據庫中的「密鑰」散列版本重新創建HMAC簽名,而不是強制客戶端 - 一面改變它的簽名生成方法(例如,避免安裝bcrypt或甚至散列祕密)?

回答

1

密碼哈希不使用共享密鑰。散列祕密的行爲應該破壞實際價值,同時保留驗證密碼的能力。你不能合理地期望從哈希中恢復密碼。

Hmac身份驗證和驗證使用共享密鑰。雙方都必須知道這個祕密。

由於這個原因,密碼散列與hmac有着根本的區別,你不能簡單地散列hmac鍵。散列不會讓你回到實際的密鑰。

[刪除澄清之後不相關的部分]

所以,你必須有某種祕密的地方,但它並不需要在數據庫中。可以使用對稱密碼(使用不在數據庫中的其他密鑰)在數據庫中對實際的hmac共享密碼進行加密。因此服務器讀取加密的hmac密鑰,解密並使用它。

重要的是你必須以某種你可以解密的方式對它進行加密,並且這可以排除哈希。

+0

感謝您澄清一些東西在這裏!我試着想想你的句子「...你通常使用其他方式進行身份驗證,然後使用hmac作爲實際的消息「,但有些服務使用與我描述的相同的方法,即使沒有額外的身份驗證......我用真實世界的示例更新了我的答案,請檢查它( ) – errata

+0

你會注意到這個例子是一個共享密鑰,你可以通過登錄來創建它來管理訪問密鑰(http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access- keys.html),然後你有責任把它交給正確的人,並保護它免受錯誤的人的保護。 –

+0

是的,我明白:)我的例子中還有一個「共享的祕密」(SUPER_SECRET_KEY)...我想知道的是如何避免將該密鑰存儲爲我的數據庫中的未加字符串... – errata