在伺服器無法解密自己的數據的情況下實現 Web 應用程序?
我是密碼學新手,但我認為世界需要盡可能地走向“加密一切”的心態。因此,我一直在思考如何建構一個 Web 應用程序,該應用程序將所有數據儲存在伺服器上,即使伺服器想要解密數據也無法解密。
這是我的想法。我很想得到回饋。
(首先讓我說一切都將通過 SSL 完成。這並不是為了保護網路上的數據,而是為了保護數據不受伺服器的影響。)
伺服器 = 任何 Web 伺服器/技術,客戶端 = JavaScript Web 應用程序
當使用者註冊或更改他/她的密碼時:
要麼由客戶提供 RSA 密鑰對(安全性高,不太方便),要麼由伺服器生成密鑰對並發送給客戶端(客戶必須相信我們不會儲存私鑰,但更方便)
此外,UUID 由伺服器生成並發送給客戶端
使用者在客戶端輸入他們的密碼——這個密碼永遠不會發送到伺服器
客戶端使用 PBKDF2 生成密鑰
此密鑰用於加密:
- 使用者的私鑰
- 從伺服器發送的 UUID
然後客戶端將以下內容髮送到伺服器:
- 公鑰
- 加密的私鑰
- 原始 UUID
- 加密的 UUID
當使用者登錄時:
客戶端將使用者名發送到伺服器
伺服器以未加密的 UUID 和新的 UUID 響應
客戶端將以下內容髮送回伺服器:
- 未加密的 UUID
- 使用與上述相同方法的 UUID 的加密副本
- 未加密的新 UUID
- 新 UUID 的加密副本
如果加密副本與伺服器上的加密副本匹配,則認為使用者已通過身份驗證,並儲存新的未加密/加密 UUID 對,以供下次使用時需要登錄
伺服器使用身份驗證令牌進行響應,該令牌用於此會話期間的所有進一步請求,以及公鑰和加密私鑰
隨著應用程序的使用
所有數據在發送到伺服器之前都使用公鑰加密,並使用客戶端中的私鑰解密。如果伺服器必須向數據庫添加內容,則使用公鑰對其進行加密,以便伺服器在生成數據時只能訪問數據。顯然,這不適用於所有案例,尤其是高度相關的數據,但我認為如果數據的結構得到普遍維護,那麼內容是什麼並不重要。
例如:
{ "username": "jsmith", "name": "John Smith", "message": "Hello there!" }
可以由伺服器處理,非常類似於:
{ "username": "U2FsdGVkX1+B9f7mMjoU9sWnYU79eN2IiDxNsetNeUI=", "name": "U2FsdGVkX188VmG67BS5lGDEs8NAUsQrG8eaVmyOlIg=", "message": "U2FsdGVkX1+7cqObxGFq2ZR3rc05NznGdoPENDujAa4=" }
因此,也許並非所有元數據都可以加密,但這絕對是朝著正確方向邁出的一步。
我希望得到回饋!就像我說的,我是一個完全的新手,所以我可以在那裡的某個地方做出一個可怕的假設,但它似乎在理論上可行……
*最後一點:*我認識到 JavaScript 並不適合加密。也就是說,我認為在這種情況下這是可以接受的,因為我們使用 JavaScript 作為 SSL 和所有其他現有安全最佳實踐之上的附加層。
所有這些問題都經過大量研究,現在仍然如此。我會嘗試為他們提供一些關鍵字。
一個 Web 應用程序,它以伺服器無法解密數據的方式將所有數據儲存在伺服器上,即使它願意。
解決方案是使用者端加密。這就是為什麼,忘記伺服器自己選擇加密密鑰的原因。
它已經很好地傳播了。當伺服器應該對數據做某事時會出現問題,因為他無法讀取它。為了解決這個問題,在同態加密方面付出了很多努力,您可以在不需要(也可能)解密數據的情況下操作加密數據。
當伺服器*“必須自己添加數據”*時,它可以使用公鑰機制,但你不能證明他沒有保留它的副本,所以這回落到保護數據免受外部攻擊者(某人例如竊取硬碟),磁碟加密應該可以完成這項工作,並且幾乎無處不在。
關於不洩露密碼的登錄方式,貌似叫做零知識密碼策略檢查(ZKPPC)。請參閱最近的這篇論文:http ://eprint.iacr.org/2014/242
首先觀察密碼是保護使用者數據免受伺服器訪問的全部。公鑰和私鑰沒有增加安全性。
這是一個簡單的解決方案,應該可以很好地工作。它甚至可能是安全的……
假設
我們依靠安全的對稱密碼系統 $ (E,D) $ 支持經過身份驗證的數據,即 $ c = E(k, ad, m) $ 和 $ m = D(k, ad, c) $ .
有兩個玩家,伺服器和客戶端。我們將假設在客戶端和伺服器之間有一個安全的、未經身份驗證的通道。
客戶有密碼 $ pw $ (由使用者輸入或從安全儲存中檢索或其他)。
客戶準備
客戶端派生兩個密鑰 $ k_a $ 和 $ k_e $ 從密碼(使用 PBKDF2 或其他)。
登記
註冊時,客戶端發送 $ k_a $ 到伺服器。它還選擇一個鍵 $ k $ 並發送 $ c_0 = E(k_e, -, k) $ 到伺服器。
聯繫
為了驗證通道,客戶端和伺服器使用 $ k_a $ 以及將身份驗證與通道聯繫起來的任何合理的相互身份驗證協議。(自從 $ k_a $ 包含有關密碼的知識,您可能希望使用基於密碼的協議。)
一旦通道被認證,伺服器立即發送 $ c_0 $ 給客戶。客戶端解密 $ c_0 $ 並恢復 $ k $ .
儲存和檢索
客戶端儲存一對元數據和明文 $ (m_0, m_1) $ 通過計算在伺服器上 $ c = E(k, m_0, m_1) $ 並發送 $ (m_0, c) $ 到伺服器。伺服器儲存該對。
客戶現在可以恢復 $ (m_0, m_1) $ 通過檢索 $ (m_0, c) $ 從伺服器和解密 $ c $ .
密碼更改
要更改密碼,使用者派生 $ k_a’ $ 和 $ k_e’ $ 根據新密碼,計算 $ c_0’ = E(k_e’, -, k) $ 並發送 $ k_a’ $ 和 $ c_0’ $ 到伺服器。