Restful HMAC認證

咱們在設計REST(Representational State Transfer)風格的Web service API,有一個問題常常要考慮,就是如何設計用戶認證的體系(Authentication). 緩存

比較傳統的作法是首先有一個登錄的API,而後服務器返回一個session ID,後續的操做客戶端都必須帶上這個session ID,可是這樣的,服務就變成了有狀態了,不符合REST風格的原則。另外,因爲負載均衡的存在,必須有公共存儲來保存用戶的Session,這也增長了系統的複雜度。 安全

因此比較好的作法是每次都傳遞認證信息,這樣系統就是無狀態的,固然因爲每次都須要認證,必然下降了一些效率,必要的時候要考慮緩存用戶信息在服務器端。 服務器

有幾點要注意: session

1.密碼不能傳播 負載均衡

一個比較低級的錯誤是通信時,由客戶端傳遞用戶名和密碼到服務器端認證,這樣很容易被黑客攻擊形成密碼泄露。 設計

標準的作法是使用HMAC(Hash-based Message Authentication Code),想法就是不傳播password,而傳播content和password的混合hash值。咱們來看看Amazon S3怎麼作認證的。 code

Amazon對每個用戶有一個AWSAccessKeyId和一個AWSSecretAccessKey,每次HTTP請求須要一個Id和一個Autherticantion信息。 好比: 同步

GET /photos/puppy.jpg HTTP/1.1 
Host: johnsmith.s3.amazonaws.com 
Date: Tue, 27 Mar 2007 19:36:42 +0000 Authorization: AWS 0PN5J17HBGZHT7JJ3X82: xXjDGYUmKxnwqr5KXNPGldn5LbA= 
這個Authorization的頭是這樣產生的: 其中YourSecretAccessKeyID用的就是AWSSecretAccessKey。 
Authorization = "AWS" + " " + AWSAccessKeyId + ":" + Signature; 
Signature = Base64( HMAC-SHA1( UTF-8-Encoding-Of( YourSecretAccessKeyID, StringToSign ) ) ); 

StringToSign = HTTP-Verb + "\n" + 
Content-MD5 + "\n" + 
Content-Type + "\n" + 
Date + "\n" + 
CanonicalizedAmzHeaders + 
CanonicalizedResource; 

CanonicalizedResource = [ "/" + Bucket ] + 
<HTTP-Request-URI, from the protocol name up to the query string> + 
[ sub-resource, if present. For example "?acl", "?location", "?logging", or "?torrent"]; 
CanonicalizedAmzHeaders = <described below> 

這樣服務端就很容易根據用戶信息來驗證信息的正確與否。 string

  1. 驗證信息的位置 hash

驗證信息能夠放在HTTP HEADER裏面也能夠放在HTTP URL裏面,象這樣: 

GET /photos/puppy.jpg?AWSAccessKeyId=0PN5J17HBGZHT7JJ3X82&Expires=1141889120&Signature=vjbyPxybdZaNmGa%2ByT272YEAiv4%3D HTTP/1.1 
Host: johnsmith.s3.amazonaws.com 
Date: Mon, 26 Mar 2007 19:37:58 +0000 

放在HTTP HEADER裏面的好處是URL比較乾淨整潔,適合放在internet與人分享,而放在URL裏面則有利於發佈私有的訪問權限給第三方。 

  1. 如何防範重放攻擊(Replay attack)? 

理論上,黑客能夠竊取你的通信報文,而後從新發送來經過認證。有幾種可能的solution. 

  1. 客戶端因此向服務器申請一個隨機數,而後這個隨機數做爲下次通信的key,一旦使用事後就當即失效,也就是所謂的」一次一密」。這種方法的好處是很安全,可是增長通信量,並且因爲負載均衡的存在,必須有公共存貯保存這個key。 

b.服務器端保存使用過的authertication信息,只要是使用過的就拒絕再次使用。這種方法不須要客戶端支持,可是須要公共空間來保持歷史記錄。 

c.使用時間戳。作法就是認證信息中含有時間信息,這樣服務器端就能夠拒絕時間相隔太長的請求,認爲其已通過期。這種作法須要服務器端和客戶端有某種形式的時間同步。 

4.要不要使用HTTPS? 

若是安全度要求很高或者是針對internet的API,無疑應該使用HTTPS,來避免內容被竊取的可能。 

若是隻是在局域網範圍或者可信賴的計算環境,則使用HTTP來提升一點效率。 

相關文章
相關標籤/搜索