簡體   English   中英

保護無會話的RESTful API端點

[英]Securing a session-less RESTful API endpoint

我為一個項目創建了一個簡單的RESTful API,部分遵循了Riyad Kalla的這篇非常好的博客文章 現在,我已經在Stack Overflow上閱讀了幾十個類似的問題,但我似乎無法找到我的安全問題的答案。

簡而言之,我的要求是這樣的:

  1. 客戶端有一個公共API密鑰(純文本,任何人都可以訪問網絡流量或正確檢查代碼源)
  2. 客戶端使用公共API密鑰向服務器發送請求
  3. 服務器有一個秘密的API密鑰(除了開發人員之外的任何人都有秘密)
  4. 服務器創建由客戶端的請求數據和秘密API密鑰組成的HMAC-SHA1哈希
  5. 服務器向API服務器發送與客戶端請求相同的請求,但包括生成的HMAC-SHA1
  6. API服務器根據它接收的公共API密鑰在其數據庫中查找秘密API密鑰
  7. API服務器使用與開發人員服務器相同的數據重新創建HMAC-SHA1哈希
  8. 如果哈希匹配,則認為該請求有效並正常處理

我擔心有人使用我的服務可以獲取公共API密鑰(通過嗅探網絡流量),然后簡單地通過他們的瀏覽器使用AJAX直接向開發人員的服務器發出相同的請求。 因此,惡意用戶可以被認證為合法用戶並使用其他秘密API密鑰訪問API。

我會嘗試舉一個具體的例子。 通常我會這樣做:

  1. AJAX向我的服務器發出get請求。
  2. 我的服務器用我的API秘密哈希我的請求並將其發送到API服務器。
  3. API服務器驗證我的請求並返回有效負載。

但我很害怕:

  1. Evil博士將嗅探我的公共API密鑰。
  2. Evil博士將使用我的公共API密鑰向我的服務器發出get請求。
  3. 我的服務器將使用我的API秘密來散布Dr. Evil的請求並將其發送到API服務器。
  4. API服務器驗證並返回有效負載以完成Dr. Evil的惡意計划。
  5. 邪惡的博士笑了起來。

我還缺少什么,或者這只是RESTful API游戲的一部分?

更新:我自願省略任何形式的時間戳驗證,以保持簡單,只關注身份驗證問題。

更新2:我已向流程添加了$_SERVER['HTTP_REFERER']驗證。 這里的目標是客戶端必須與請求一起發送引用者,並且它必須與API側數據庫中列出的引用者匹配。 不幸的是,HTTP引用可以很容易偽造。 這是另一個安全級別,但仍然不完美。

更新3:我已經更改了服務器端代碼,將引用者設置為遠程IP地址。 這會強制發送到我的服務器的每個請求使用秘密API密鑰進行哈希處理,最終使用原始請求IP地址到達API服務器。 然后可以驗證此IP並且請求可以通過。 我相信它還有可能偽造$_SERVER['REMOTE_ADDR'] ,但它比偽造$_SERVER['HTTP_REFERER']更復雜......我想還是不完美。

更新4 :根據這些帖子: 如何偽造$ _SERVER ['REMOTE_ADDR']變量? https://serverfault.com/questions/90725/are-ip-addresses-trivial-to-forge ,偽造$_SERVER['REMOTE_ADDR']雖然很難。 但是,由於您無法控制偽造網絡,因此無法接收偽造請求的響應。 該請求可以成功驗證,但其響應不會落入惡意手中。

通過使用HMAC,您走在正確的軌道上。 但是,還有兩件事可以使您的應用程序更安全。

  1. 在客戶端POST中需要時間戳,需要在服務器時間的5分鍾內驗證。 它也應該包含在HMAC生成中。 如果有人試圖更改此設置,則HMAC簽名將無效,除非他們具有更新HMAC簽名的密鑰。
  2. 使用SSL,進行證書驗證。 防止中間人攻擊。 不允許任何非ssl請求。

我發現阻止其他腳本使用公共API密鑰並向服務器端HMAC哈希腳本發送請求的解決方案是發送原始請求者的身份以及請求。 我正在使用$_SERVER['REMOTE_ADDR']來確定原始請求者的身份,因為它更難偽造,偽造它通常意味着他們不會得到響應。

/* $this as a class that handles requests */

// Build hash and include timestamp
$this->vars['timestamp'] = time();
$this->vars['hash'] = hash_hmac('sha1', http_build_query($this->vars).$this->vars['token'], API_SECRET);

// Send request to API
curl_setopt_array($this->curl, array(
    CURLOPT_RETURNTRANSFER => 1,
    CURLOPT_URL => $url,
    CURLOPT_POST => $this->method == 'post' ? 1 : NULL,
    CURLOPT_POSTFIELDS => $this->method == 'post' ? $this->vars : NULL,
    CURLOPT_CONNECTTIMEOUT => 15,
    CURLOPT_TIMEOUT => 15,
    CURLOPT_REFERER => $_SERVER['REMOTE_ADDR'], // Referer here!
    CURLOPT_MAXREDIRS => 3,
    CURLOPT_HTTPGET => $this->method == 'get' ? true : false
));

一旦發送,API不僅會檢查數據庫中的秘密API密鑰,還會檢查$_SERVER['HTTP_REFERER']是否被列為允許! 這也允許API基於每個用戶接受服務器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM