2011-12-04 28 views
2

我在AppEngine上運行REST服務(可能不相關)。每個REST請求都伴隨着一個用戶標識和密碼,並且在每個請求開始時,我會散列密碼以查看它是否與我的記錄匹配,然後再繼續。通過多個請求進行高效密碼散列

理論上這很好,但在實踐中,我得到了來自用戶的請求--4秒或5秒。這需要BCrypt 500ms來爲每個請求散列密碼!真是太浪費了!

顯然,我不想優化BCrypt的時間。是否有緩存哈希的標準做法? memcache會是一個安全的地方,用於存儲最近散列的密碼錶及其哈希表?我想在這一點上,我可能會將用戶的純文本密碼存儲在Memcache中。我很樂意做一個3ms的memcache查找,而不是500ms的哈希,但是安全是最重要的。實施某種類型的會話抽象會更有意義嗎?

感謝您的任何建議!

編輯額外的上下文:這是一個存儲敏感的學生數據(成績)的成績簿應用程序。教師和學生從任何地方登錄,包括通過wifi等。每個成功的請求都通過https發送。

+0

哇,不會期望谷歌應用程序引擎操作的基礎,因爲這需要這麼長的時間......發佈會話cookie是相當標準的,但如果不在安全的連接上,則會遭到盜竊/劫持......關於您的應用程序的更多上下文可能會幫助ppl提供更有用的答案 - 您可接受的容差是什麼......這是一個銀行應用程序嗎? (懷疑它,如果託管在谷歌應用程序,但只是一個理論問題......) – Nathan

+0

@Nathan:這裏的問題的一部分是,bcrypt是*假設*慢(http://en.wikipedia.org/維基/ Key_stretching)。但是正如Rhuidean所說,你可以使用密碼來建立一個會話密鑰,它可以是(a)大的,(b)隨機的,(c)短暫的,因此更難以暴力破解,無論是在線如果攻擊者以某種方式獲取了存儲的會話密鑰的散列值,那麼請求或服務器淹沒服務器。因此,對於會話密鑰,您可以使用較少的哈希輪次數 - 對於大多數情況下,我認爲您可以使用零輪次並存儲普通會話密鑰。 –

+0

@Nathan:我在OP中添加了你正在尋找的上下文。感謝關於會話密鑰更快散列的想法,@SteveJessop;我想如果我走這條路,我可能會用零,但我沒有想過調整難度。 –

回答

1

考慮到您目前的做法,最好的方法是在memcache中保留密碼嘗試映射到他們的加密形式。如果您擔心在memcache中存儲明文密碼的原因,請將嘗試密碼的md5sha1散列代替作爲密鑰。

額外的步驟並不是真的有必要。存儲在memcache中的項目不會泄漏到其他應用程序。

+0

我想要檢查的是,「在運行我的應用程序的進程的內存中,memcache中的敏感數據是否比敏感數據更能泄漏?」。如果答案是「否」,看起來相當可能,那麼緩存密碼並不比處理密碼差。如果答案是「是」,那麼你必須決定風險的差異是否跨越你關心的某個門檻。 –

+0

謝謝你的答案,戴夫!我繼續前進並實現了這一目標,幾乎每個請求都減少了500毫秒,對於某些請求來說,它的速度提高了95% - 並且對API的客戶端來說它是透明的。我很高興看到今天的結算信息;) –

2

REST API的常規經驗法則是讓它們保持完全無狀態,但是,與轉換有時間和地點取決於您的要求。如果你不反對讓客戶端存儲一個臨時會話密鑰的想法,你只需要偶爾重新生成,那麼你可以嘗試一下。

當客戶端發出請求時,檢查他們是否發送會話密鑰變量以及用戶標識和密碼。如果不是,請根據當前服務器時間和密碼生成一個,然後將其傳回客戶端。將它與創建時間一起存儲在您自己的數據庫中。然後,當客戶端發出包含會話密鑰的請求時,您可以直接將其與數據庫中存儲的會話密鑰進行比較而無需散列驗證。只要你每隔幾個小時使密鑰無效,它就不應該成爲一個安全問題。再次,如果您當前正在發送密碼和用戶標識,那麼您已經有安全問題。

+1

「不需要散列」 - 或者如果您擔心這一點,那麼使用比EKSBlowfish快得多的散列。 –

+0

我可以讓會話密鑰可選,我想可以保護API的無狀態,以便客戶端使用它,但允許客戶端使用會話加快速度。感謝您的建議。我唯一不喜歡的是它需要一個特殊/ getsession請求,或者在響應中的額外信息。 ps:我通過https發送每個請求並將用戶標識/密碼cookie標記爲安全,因此它們永遠不會以明文形式發送 –

+0

如果您以XML/JSON或其他關係格式的形式返回數據,我建議在響應中包含會話密鑰。但是,您只需在第一次身份驗證時或會話密鑰過期時執行此操作,這是您可以根據服務器負載進行控制的時間段。 – wrren