2011-11-21 120 views
11

我正在爲一組網站設計API。這些站點非常相似(有點像StackOverflow,SuperUser和ServerFault),並且他們有一個共享的後端是合理的。因此,我們決定嘗試使用一個很好的REST API作爲後端,以及一些使用API​​的非常相似但不同的前端。前端應該最好全部是靜態的,但如果事實證明這是不可能的,那麼這並不是一個硬性要求。如何保護瀏覽器從CSRF攻擊中使用的RESTful API?

我正在設計API,我擔心安全問題,特別是CSRF。從我對CSRF攻擊的基本理解來看,它們包含兩個重要組件:

  1. 能夠命名資源和請求正文。

  2. 欺騙用戶/瀏覽器使用環境認證(如會話)向該資源尋求認證的請求。

很多修復CSRF攻擊的經典方法都基於會話。由於我的REST API並沒有真正執行會話,因此它們都會阻止很多向量,並且幾乎可以解決所有這些問題。例如,雙提交沒有意義,因爲沒有什麼可以提交。

我最初的方法是攻擊CSRF攻擊的第2部分。如果我對所有請求進行了身份驗證(比如使用HTTP Basic Auth),並且瀏覽器不保存這些證書(例如,某些JS發出請求),那麼只有擁有憑證的JS才能發出請求,並且我們完成了。明顯的缺點是應用程序需要知道用戶的憑據。另一個稍微不太明顯的缺點是,如果我想在API端安全地存儲憑據,那麼驗證密碼應該花費固定的,不重要的時間量。如果安全地驗證密碼需要100ms,那麼其他每個請求至少需要100ms + eps,並且這會讓一些聰明的客戶端欺騙手段使其不那麼慢。我可能能夠緩存這些信息(因爲證書總是相同的),如果我非常小心,我可能會設法做到這一點,而不會引入定時漏洞,但這聽起來像是一個黃蜂巢。

OAuth 2.0似乎有點過分了,但我想這可能是最好的解決方案,以免我最終實施得不好。我想我現在可以做HTTP基本身份驗證的事情,當我們有第三方應用程序開發人員時,轉到OAuth。

OAuth有一點阻抗不匹配。基本上,OAuth真的想幫助應用程序訪問另一個應用程序的內容。我希望用戶在這樣一個帳戶存在之前註冊其中一個前端。

我也考慮過攻擊點1,通過使URL隨機化 - 即將標記添加到查詢字符串。這肯定會起作用,它與表單中傳統的隨機化令牌非常接近,並且給予HATEOAS它應該甚至是相當RESTful,儘管這提出了兩個問題:1)您從哪裏開始?在使用HTTP Basic Auth進行登錄時,是否有必要的API起始點? 2)如果他們不能事先預測URL,HATEOAS會被定罪嗎?

我看過How to prevent CSRF in a RESTful application?,但我不同意這樣一個前提,即隨機化的URI必然是不可靠的。另外,這個問題並沒有真正的答案,也沒有提到OAuth。此外,會話雙提交解決方案是無效的,正如我上面提到的(靜態前端的不同域比API端點)。

我意識到我從根本上試圖在這裏做的是試圖允許來自一個域的跨站點請求,並禁止從另一個域請求,這並不容易。當然必須有一些合理的解決方案?

+0

的問題,就像你說的,是要既防止和允許跨站點請求。問薛定諤。 –

+0

這並不意味着沒有辦法解決問題。我甚至提供了一個,儘管有點慢。 – lvh

回答

0

答案取決於你需要支持什麼。如果我們假設您想要支持一個網頁應用程序,其中使用 REST服務,並使用相同的REST服務用於與恰好是RESTFUL的網絡應用程序不同的API(您可以決定「會話」是爲了你!)。

現在(/我很累)我認爲你已經建議在HTTP Basic Auth中使用javascript的方式是一個好的開始。

+0

HTTP基本身份驗證容易受到CSRF的影響。 – rook

+0

你能不能詳細說明一下?我意識到瀏覽器緩存HTTP基本身份驗證,但我們並沒有要求瀏覽器去做;我們建議讓一些JS構建HTTP基本身份驗證標頭。因此證書永遠不會在瀏覽器的環境auth池中結束,並且系統變得不受CSRF影響。正確? – lvh

3

CSRF令牌按照定義爲「每用戶狀態」,因此不是RESTful。出於安全目的,大多數API都會打破其「每用戶狀態」要求,並且需要將CSRF令牌作爲HTTP標頭參數傳遞。

還有其他方式preventing CSRF。檢查引用者並不像CSRF令牌那麼強大,但它是RESTful的,並且不太可能被破壞。請記住,缺乏引用者應被視爲失敗的請求。

XSS可用於繞過基於令牌的CSRF預防和基於引用的CSRF預防。

+0

與我在回覆您的評論時的評論相同。您能否詳細說明爲什麼在使用JS添加身份驗證標頭時,HTTP基本身份驗證不會阻止CSRF?另外,OAuth如何不阻止CSRF? OAuth的一次性令牌部分不能保證嗎? – lvh

+0

@lvh用戶名和密碼是與請求一起發送的每用戶狀態。用作CSRF令牌的加密隨機數也是每個用戶狀態隨每個請求一起發送的,但它更安全,因爲它應該是與會話相關的動態值。通常,RESTful協議依賴於靜態密碼nocne或「api密鑰」,它是每個用戶的狀態並且也停止CSRF。在HTTP標頭中發送它並不會讓它變得安靜,但如果瀏覽器發送的其他請求包含此值,則可能會打開攻擊的大門。 – rook

+0

但這就是我的觀點。如果它不成爲環境瀏覽器授權,攻擊媒介是什麼?對於CSRF而言,它是一個隨機數還是實際憑證並不重要:瀏覽器不知道*,因此如何欺騙它以提供它? – lvh

0

我有另一個潛在的解決方案,所以我列出它作爲答案。請隨意分開:)

auth.platform.com需要身份驗證並設置cookie。如果auth.site.comauth.platform.com一個CNAME,將請求auth.site.com(在auth.platform.com分辨率之後結束了)可以設置cookie爲site.com?這樣我可以雙重提交會話cookie。

當然,auth.platform.com將只有幾個白名單域設置的Cookie。

編輯:當然,除了這不會在所有的工作,因爲你不得不使用HTTPS安全地做認證和HTTPS會看到右邊通過你的詭計。

0

設計你的API作爲一個真正的RESTful,防止最常見的CSRF載體:使用GET爲「安全」的操作

  • 避免餅乾防止它們被「偷走」,
  • 防止imgiframes在沒有用戶交互的情況下觸發不安全的操作。

然後,您應該實施CORS以讓用戶的瀏覽器阻止來自您不信任的來源的請求。

+1

-1除了關於CORS的評論外,這與CSRF沒有任何關係。 CORS是危險的,可以用來讀取CSRF令牌或其他敏感信息。 CORS不能用於防止CSRF。 – rook