為什麼所有 API 都使用對稱密鑰而不是公鑰?
我曾經註冊過的每個 API 都會為您提供一個密鑰,然後您可以將其粘貼到您的應用程序中。他們知道鑰匙,你也知道。(一個例外可能是 VAPID for Web Push)。
為什麼會這樣?一些應用程序和協議已經為使用者提供了一個公鑰/私鑰對,並且只將公鑰儲存在使用者的數據庫行中。然後,使用者使用其相應的私鑰簽署請求,這些私鑰永遠不會離開設備。(沒關係,在 Web3 錢包中,您通常可以導出私鑰,我認為這是一個糟糕的設計決策,會導致各種網路釣魚和詐騙。)
現在,我知道對於加密,我們確實需要在有效負載旁邊發送一個對稱密鑰來解密它。但是對於簡單地對有效負載進行簽名,我們不能只對其進行雜湊處理並使用私鑰對雜湊進行簽名嗎?
我能想到的使用對稱密鑰的唯一理由有可怕的缺陷:
- **機構。既然平台無論如何都在做這項工作,那麼知道對稱密鑰有什麼害處呢?**嗯,這有兩個問題。一是如果平台的數據庫被攻破,所有的秘密都會被洩露。其次是平台可能會冒充應用程序,假裝應用程序簽署了一些東西,而實際上它沒有。更改數據庫狀態是一回事,聲稱應用程序或使用者要求您這樣做是另一回事。
- **量子電阻。當量子電腦能夠破解橢圓曲線密碼學等時,任何擁有足夠資源的人都可以模擬應用程序的請求。**嗯,這是真的,但到時候我們可以切換到使用 SPHINCS+,它也是基於散列,或者可能是基於格的密碼學。確實,我們需要時間來切換應用程序,但除非您正在建構分佈式協議,否則您可以通過簡單地更改平台來強制他們進行操作。
- **舊版本的 PHP 不支持開箱即用的公鑰加密,我們不希望我們的使用者必須安裝自定義 PHP 擴展。**對於 Wordpress、Discourse 和其他旨在自託管的開源平台,我可以理解這一基本原理。但是現在所有的語言都支持開箱即用。所以有什麼問題?另外,大多數 API 都是由中心化公司執行的,所以這不是問題。
簡而言之,我不明白為什麼 API 使用共享密鑰而不是其 API 客戶端的公鑰。
我認為將這些類型的令牌稱為“對稱密鑰”是沒有意義的,因為它們不是用作對稱密碼輸入的加密密鑰。它們是不記名令牌,在傳輸過程中受到完全獨立的加密系統(通常是 TLS)的保護。它們通常被稱為“API 密鑰”,但這與“密鑰”一詞在密碼學上下文中的使用方式無關。
我認為你的問題的答案是,非對稱加密比使用不記名令牌更複雜,沒有提供任何有意義的優勢。
您建議使用非對稱加密的唯一論點是:
一是如果平台的數據庫被攻破,所有的秘密都會被洩露。
通常,受身份驗證/授權系統保護的數據比身份驗證令牌本身更有價值。(例外情況是可能在多個站點中重複使用的密碼,但這不是隨機生成的 API 密鑰的問題。)
如果攻擊者可以完全破壞平台的數據庫,他們就不需要進行身份驗證。他們可以直接檢索(或更改)敏感數據。令牌被洩露並不重要。
另一方面,如果單個使用者的令牌被洩露,您始終可以撤銷他們的令牌,就像如果他們的私鑰被某種方式洩露,您可以撤銷他們的公鑰一樣容易。
其次是平台可能會冒充應用程序,假裝應用程序簽署了一些東西,而實際上它沒有。更改數據庫狀態是一回事,聲稱應用程序或使用者要求您這樣做是另一回事。
好的,但沒那麼簡單。您正在談論使系統能夠以加密方式證明其目前狀態是僅授權使用者操作的結果。這意味著請求不僅必須進行數字簽名,而且還必須儲存在某個地方的永久日誌中。你必須能夠證明目前狀態是重建所有這些動作的結果。這大大增加了實現的複雜性。
有一些系統以這種方式工作——特別是 Git(帶有簽名送出)和各種區塊鏈——但對於大多數應用程序來說,使用者對這種可驗證性水平的需求並不大。在大多數情況下,如果使用者認為您的系統故意篡改他們的數據,他們不會浪費時間要求進行密碼驗證。他們只會停止使用它。
(當然,即使是數字信任鏈也不能真正證明授權使用者是執行請求的人,因為他們的密鑰可能已被洩露。)
如果我正在與使用對稱密鑰的 API 端點交談,我可以在命令行上使用 cURL 輕鬆呼叫它或在 Javascript 中獲取。初級開發人員可以在幾分鐘內與 API 集成。
如果我想簽署我的請求,我需要使用第三方庫。這大大增加了開發人員的時間和集成的複雜性。該服務會產生更多的支持成本來幫助開發人員解決集成問題,並且需要更多的工作來查找和提供程式碼範例,以開發人員可能希望使用的所有不同語言的簽名庫。
以我自己的個人經驗,通過簡單的 HTTPS 呼叫訪問的庫的文件質量遠高於該服務為各種不同語言提供的單個庫的文件。只有擁有大量預算的大公司才能負擔得起在開發、記錄、維護和支持十幾個不同的庫方面做得很好。