2011-08-30 60 views
72

設計REST API時,通常先驗證用戶身份?在不重新發明輪子的情況下保護REST API

我要找的典型使用情況是:

  • 用戶希望得到的數據。當然很酷,我們喜歡分享!獲取一個公共API密鑰並閱讀!
  • 用戶想要存儲/更新數據......哇等等!你是誰,你能做到嗎?

我想構建一次,並允許說一個網絡應用程序,Android應用程序或iPhone應用程序來使用它。

一個REST API似乎是這樣

要求要說明我的問題,我會用一個簡單的例子,一個合乎邏輯的選擇。

我有一個數據庫中的項目,它有一個評分屬性(整數1到5)。

如果我理解REST正確我會實現使用我選擇的返回CSV,XML或JSON這樣的語言GET請求:

http://example.com/product/getrating/{id}/ 

說我們挑JSON我們返回:

{ 
    "id": "1", 
    "name": "widget1", 
    "attributes": { "rating": {"type":"int", "value":4} } 
} 

這對於面向公衆的API來說很好。我得到那部分。

我在哪裏有很多問題,我該如何將它與安全模型相結合?我習慣了網絡應用程序的安全性,我有一個會話狀態隨時可以識別我的用戶,所以我可以控制他們可以做什麼,無論他們決定發送給我什麼。據我瞭解,這不是RESTful,所以在這種情況下將是一個不好的解決方案。

我會嘗試使用另一個使用相同項目/評級的例子。

如果用戶「JOE」想要一個評級添加到項目

這可以通過使用來完成:

http://example.com/product/addrating/{id}/{givenRating}/ 

在這一點上我想存儲的數據說「 JOE「給出了產品{id}的評分{givenRating}。

問:我怎麼知道請求來自「JOE」而不是「BOB」。

此外,如果是用戶的電話號碼等更明智的數據呢?

到目前爲止,我已經得到了什麼是:

1)使用內置的HTTP的功能,在每個請求進行身份驗證,無論是普通的HTTP或HTTPS。

這意味着,每一個要求,現在採取的形式是:

https://joe:[email protected]/product/addrating/{id}/{givenRating}/ 

2)使用諸如亞馬遜的S3與私人和公共密鑰的方法:http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/

3)仍要使用一個Cookie,並打破REST的無狀態部分。

第二種方法對我來說似乎更好,但我還是想知道我是否真的必須重新創造這整個事情?散列,存儲,生成密鑰等都由我自己?

這聽起來很像在典型的Web應用程序中使用會話並且自己重寫整個堆棧,通常我的意思是「你做錯了」,特別是在處理安全性時。

編輯:我想我應該提到OAuth以及。

+4

如果您發送每個請求的用戶名和密碼,請使用HTTPS **。 –

+51

與安全無關,但RESTful API不會使用'getrating'和'andrating';它只是「評級」,你會GET,POST,PUT或DELETE到該資源。 – Duncan

回答

20

編輯5年以後

使用的OAuth2!

以前版本

沒有,絕對沒有必要使用Cookie。它不如HTTP摘要,OAuth或亞馬遜的AWS(這不難複製)安全一半。

您應該查看Cookie的方式是,它與Basic/Digest/OAuth /以較高者爲準,但不太合適。

但是,只要會話cookie的內容不影響您從服務器返回的資源內容,我並不認爲使用cookie會違反REST風格的原則本身

餅乾是邪惡的,停止使用它們。

+2

我沒有發現亞馬遜的方式難以複製每一個說......像我沒有發現從頭開始寫JavaScript「硬」,但jQuery肯定幫助寫好。閱讀它讓我想知道是不是有一個抽象的框架? – jfrobishow

+1

谷歌它。我爲AWS編寫了一個實現,但它並不完整,我相信:http://code.google.com/p/sabredav/source/browse/lib/Sabre/HTTP/AWSAuth.php – Evert

+2

對不起,但答案不正確。 Cookie和HTTP摘要是互補的但是正交的 - 您可以使用第二個來驗證用戶併發布cookie。與OAuth相比,基於cookie的安全性在您擁有跨域服務時不起作用,或者您讓其他不受信任的人將客戶端寫入您的服務(涉及第三方)並希望允許您的用戶撤銷應用程序訪問。但在其他情況下,它的工作方式與OAuth完全相同,您可以將Cookie作爲OAuth訪問令牌進行考慮,這也是您需要在某處存儲的方式。 – zihotki

21

不要擔心「RESTful」,擔心安全問題。以下是我的工作方式:

步驟1:用戶使用憑據訪問身份驗證服務。

步驟2:如果憑證檢出,返回一個指紋,會話ID等等,並將它們彈出到共享內存中以便以後快速檢索或使用數據庫,如果您不介意將幾毫秒添加到您的Web服務週轉時間。

步驟3:向每個Web服務腳本的頂部添加一個入口點調用,該腳本驗證每個 Web服務請求的的指紋和會話ID。

第4步:如果指紋和會話ID無效或超時重定向到身份驗證。

這樣說的:

RESTful Authentication

+3

但是,那麼在每次「會話」過期之前訪問API之前都不要強制用戶登錄?如果是移動設備,你會怎麼做?給他們一個永久的「鑰匙」,這樣他們就不必每次使用應用程序時都使用API​​登錄? – jfrobishow

+1

我強制他們登錄。它不是那個,就是使用cookie,或者將指紋映射到他們的UDID,但是UDID就意味着用戶必須從同一個設備訪問服務。 –

+0

關於第3步:這意味着如果我使用的是「控制器」內使用「Actions」的MVC框架,我應該在每個Action中加入兩個額外的參數(指紋和sessionid)? – sports

7

編輯3年後

我完全同意埃弗特,使用OAuth2使用HTTPS,不推倒重來! :-)

通過更簡單的REST API - 不適用於第三方客戶端 - JSON Web Tokens也可以。

以前版本

仍要使用一個Cookie,打破REST的無狀態的一部分。

不要使用會話,使用會話您的REST服務將不會很好的擴展......這裏有兩種狀態:應用程序狀態(或客戶端狀態或會話)和資源狀態。應用程序狀態包含會話數據,並由REST客戶端維護。資源狀態包含資源屬性和關係,並由REST服務維護。你可以很容易地決定一個特定的變量是應用程序狀態還是資源狀態的一部分。如果數據量隨着活動會話的數量而增加,則它屬於應用程序狀態。因此,例如,當前會話的用戶身份屬於應用程序狀態,但用戶列表或用戶權限屬於資源狀態。

因此,REST客戶端應該存儲識別因子並將其發送給每個請求。不要將REST客戶端與HTTP客戶端混淆。他們不一樣。如果REST客戶端使用curl,它也可以在服務器端,或者它可以創建例如服務器端http only cookie,它可以通過CORS與REST服務共享。唯一重要的是REST服務必須通過每個請求進行身份驗證,因此您必須隨每個請求一起發送憑據(用戶名,密碼)。

  • 如果您編寫客戶端REST客戶端,則可以使用SSL + HTTP身份驗證完成此操作。在這種情況下,您可以在服務器上創建credentials -> (identity, permissions)緩存以加快身份驗證。請注意,如果您清除緩存並且用戶發送相同的請求,則它們將得到相同的響應,只需要更長的時間。您可以將其與會話進行比較:如果您清除會話存儲區,則用戶將得到一個status: 401 unauthorized響應...
  • 如果您編寫服務器端REST客戶端,並通過curl將識別因子發送到REST服務, 2個選擇。您也可以使用http auth,或者您可以在REST客戶端中使用會話管理器,但不能在REST服務中使用。
  • 如果有人不信任地寫入您的REST客戶端,那麼您必須編寫一個應用程序來對用戶進行身份驗證,併爲他們提供可用性以決定他們是否要將權限授予不同的客戶端。 Oauth是一個已經存在的解決方案。 Oauth1更安全,oauth2不太安全但更簡單,我想這個問題還有其他幾個解決方案......你不必重新創建這個。有完整的使用oauth的認證和授權解決方案,例如:wso identity server

餅乾不一定是壞的。您可以以RESTful方式使用它們,直到它們保持客戶端狀態並且服務僅保持資源狀態。例如,您可以將購物車或首選的分頁設置存儲在Cookie中...

+1

這是怎麼回事?不要擔心是「RESTful」,擔心安全問題。 –

+0

太晚了,我不知道你在說什麼,對不起。 :D明天我會讀這篇文章,我不記得它... – inf3rno

+2

我設法再次閱讀這篇文章。葉普,我認爲這是因爲我的帖子比你提到的帖子延遲了2年。就這樣,祝你有個愉快的夜晚! :-) – inf3rno

相關問題