如何實現RESTful Web API的身份驗證

最近想拿一個小項目來試水RESTful Web API,項目只有幾個調用,比較簡單,但一樣須要身份驗證,若是是傳統的網站的話,那不用說,確定是用戶名+密碼在登陸頁得到登陸Token,並把登陸Token記在Cookie和Session中做爲身份標識的這種方式,但如今不一樣了,關鍵是RESTful,這意味着咱們設計出來的這些API是無狀態的(Stateless),下一次的調用請求和這一次的調用請求應該是徹底無關的,也就是說,正宗的RESTful Web API應該是每次調用都應該包含了完整的信息,沒錯,包括身份信息!數據庫

那如何確保安全?傳輸時給密碼作MD5加密?得了吧!這樣作只能讓你本身感受「安全」點,其實沒什麼任何用處,利用如今的技術(有種叫什麼Rainbow Table啥的來着?本人外行,不是很懂)很快就能算出明文密碼了,並且如何防止挾持和重發攻擊?api

也許你想到了,SSL,若是你打算採用SSL,請忘記一切自行設計的加密方案,由於SSL已經幫你作好了一切,包括防止監聽,防止挾持,防止重發……一切都幫你考慮好了,你大膽地把明文密碼寫在你的包中就OK了,我向你保證沒問題。緩存

但SSL的缺點是服務器端配置相對有點複雜,更關鍵的就是客戶端對此支持可能很差,那你考慮一種本身的加密方法,有木有?我這裏提供一種方法,思路來自於:http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/,我只是把上面的內容中整理了一下變成了個人方法。(傳說中的剽竊?呵呵)方法描述以下:安全

  1. 假設有一個用戶,用戶名是guogangj,密碼是123456(呃……這也能叫密碼?)
  2. 他要GET http://test.com/api/orders/
  3. 因而把 http://test.com/api/orders/這個URL和一個新生成的GUID拼在一塊兒,再用123456這個密碼執行對稱加密,生成的密文爲XXXXOOOOXXXXOOOO(假設而已)
  4. 數據包中帶上用戶名guogangj和XXXXOOOOXXXXOOOO這個密文,發送給服務器
  5. 服務器收到包後,根據guogangj這個用戶名到數據庫中查找到123456這個密碼
  6. 服務器使用123456這個密碼來解密XXXXOOOOXXXXOOOO這個密文,獲得了明文,即http://test.com/api/orders/這個URL和前面由客戶端生成的那個GUID
  7. 服務器到一個全局的集合中查找這個GUID,看看是否已經存在,若是存在,則驗證不經過,若是不存在,就將其放入這個集合中。這是爲了不重發攻擊。這個全局的集合會愈來愈大,因此還要按期清理。
  8. 服務器再比對解密出來的URL和用戶真實請求的URL是否一致,若是一致,那麼認爲這是合法用戶,驗證經過!

這是大體過程,若是數據庫裏找不到該用戶,或者解密錯誤,都被認爲驗證不經過。如下是一些改進:服務器

  1. 數據庫中的密碼最好作一下摘要(MD5之類的),客戶端對應地也要作一下。
  2. 在生成密文的時候能夠考慮加入另一些不但願被明文傳輸的敏感內容,甚至能夠加入IP地址,並在服務器端驗證。
  3. 並不是每次都要真正去數據庫裏拿一次用戶信息,也許你有更好的辦法,好比一個簡單的緩存(不過須要處理緩存更新的問題),或者當你的系統大到必定程度的時候,你考慮使用統一的服務來獲取用戶信息,這就不是緩存那麼簡單了,裏面的文章不少,我相信如今大規模的門戶網站都有本身的一套複雜的機制,因此代表上看RESTful Web API很「低效」,但這種RESTFul的思路和模式卻在實際中有很大的可塑性和威力。

這種方法應該足夠安全了!網絡

密碼根本沒有在網絡上傳輸,密文采用的是非驗證的對稱加密,沒有密鑰就沒法逆轉,URL驗證避免了傳統的身份挾持攻擊(即攔截一個用戶的包並冒充此用戶來訪問其它的資源,即使沒法破解用戶密碼), 再用GUID來避免了重發攻擊,惟一須要擔憂的是用戶泄露了本身的密碼。less

元芳,你怎麼看?

網站

相關文章
相關標籤/搜索