結合網上找的資料整理了一下,以下是web開發中常見的鑒權方法:
預備:一些基本的知識
RBAC(Role-Based Access Control)基於角色的權限訪問控制(參考下面①的連接)
l 用戶-角色-權限 的授權模型 : 一個用戶擁有若干角色,每一個角色擁有若干權限
l 用戶:一個個獨立的賬號
l 角色:一些權限的集合,是權限的載體(例如:"管理員"、”會員“、"普通用戶")
l 權限:權限通常是一組資源的集合。(例如:用戶管理、保單管理、系統維護。角色和權限是多對多關系。)
l 用戶量大的時候,單獨為一個用戶授予角色比較繁瑣,需增加用戶組,可以對用戶組內所有的用戶統一分配角色,這樣一來,用戶擁有的所有權限,就是用戶個人擁有的權限與該用戶所在用戶組擁有的權限之和。
l 各種資源的整合,我們在設計權限的時候會遇到多種類型的資源,例如頁面元素的顯示隱藏、文件的訪問、按鈕的操作權限等等
ACL 訪問控制列表,是前幾年盛行的一種權限設計,它的核心在於用戶直接和權限掛鈎。
RBAC的核心是用戶只和角色關聯,而角色代表對了權限,這樣設計的優勢在於使得對用戶而言,只需角色即可以,而某角色可以擁有各種各樣的權限並可繼承。
ACL和RBAC相比缺點在於由於用戶和權限直接掛鈎,導致在授予時的復雜性,雖然可以利用組來簡化這個復雜性,但仍然會導致系統不好理解,而且在取出判斷用戶是否有該權限時比較的困難,一定程度上影響了效率。
基於RBAC模型的權限驗證框架與應用
Apache Shiro
Spring Security
SELinux
Cookie 有時也用其復數形式 Cookies,指某些網站為了辨別用戶身份、進行 session 跟蹤而儲存在用戶本地終端上的數據(通常經過加密)
l 位於客戶端
l cookie由服務器生成,發送給瀏覽器,瀏覽器把cookie以kv形式保存到某個目錄下的文本文件內,下一次請求同一網站時會把該cookie發送給服務器
l 由於cookie是存在客戶端上的,所以瀏覽器加入了一些限制確保cookie不會被惡意使用,同時不會占據太多磁盤空間,所以每個域的cookie數量是有限的。
l 傳遞過程:
n 瀏覽器向某個 URL 發送請求
n 對應的服務器收到該 HTTP 請求,生成要發給瀏覽器的 HTTP 響應
n 在響應頭中加入 Set-Cookie 字段,值為要設置的的Cookie
n 瀏覽器收到來自服務器的 HTTP 響應
n 瀏覽器在響應頭中發現了 Set-Cookie 字段,就會將該字段的值保存在內存或者是硬盤中。
n 當下一次向該服務器發送 HTTP 請求時,會將服務器設置的 Cookie 附加在 HTTP 請求的字段 Cookie 中。
n 服務器收到這個 HTTP 請求之后,發現請求頭中有 Cookie 字段,就知道了已經處理過這個用戶的請求了。
n 過期的 Cookie 會被刪除
n 這里注意下:上面的步驟中cookie是通過服務端下發的,但是cookie是一種客戶端技術,也可以客戶端腳本通過讀取返回的正文解析出結果,然后寫入cookie同樣能達到相同的效果
Session 在計算機中,尤其是在網絡應用中,稱為“會話控制”。Session對象存儲特定用戶會話所需的屬性及配置信息。
l 位於服務端
l session的創建目的初衷就是為了讓服務端記住會話,簡而言之就是讓服務端能識別出來是哪個客戶端
l 每次客戶端發起請求的時候帶上Session的標識,然后服務端就知道是誰來訪問的了,這個標識可以通過上面的Cookie保存在客戶端,這樣兩者就有了關系
Cookie和Session的關系:
session和cookie的目的相同,都是為了克服http協議無狀態的缺陷,但完成的方法不同。
session可以通過cookie來完成,在客戶端保存session id,而將用戶的其他會話消息保存在服務端的session對象中。
cookie需要將所有信息都保存在客戶端。因此cookie存在着一定的安全隱患,例如本地cookie中保存的用戶名密碼被破譯,或cookie被其他網站收集(例如:1. appA主動設置域B cookie,讓域B cookie獲取;2. XSS,在appA上通過javascript獲取document.cookie,並傳遞給自己的appB)。
XSS攻擊和CSRF攻擊:
XSS(Cross Site Scripting) 跨站腳本攻擊,為不和層疊樣式表(Cascading Style Sheets, CSS)的縮寫混淆,故將跨站腳本攻擊縮寫為XSS。具體可參考7
CSRF(Cross-site request forgery):跨站請求偽造。具體可以參考8
防御 CSRF 攻擊主要有三種策略:
- 驗證 HTTP Referer 字段;
- 在請求地址中添加 token 並驗證;
- 在 HTTP 頭中自定義屬性並驗證。
認證和授權
認證和授權是兩個不同的概念,更是兩個不同的階段,絕大多數帶有認證和授權的系統,在用戶操作流程上都是先進行認證,之后根據認證的結果再進行授權操作。
認證是用來證明一個用戶身份的操作流程,授權是用來給當前用戶賦予權限的操作流程
一. API Key + API Secret
實現步驟:
1.服務端和客戶端約定好,API Key 以及 API Secret,服務端進行保存,下發給客戶端
2.客戶端發起請求的時候,客戶端使用 API Key +API Secret + 其他參數 (加密算法) 生成簽名字符串 sign1,把 API Key 、其他參數 和 sign1 一起發送給服務器 (API Secret 不發送)
3.服務接收到了客戶端發來的請求,將通過其中的API Key找到API Secret,然后按照和客戶端約定好的加密方式再進行計算一次,生成一個 sign2
4.服務端比較Sign2和Sign1是否相同來判斷是否可以讓客戶端進行訪問。
關鍵點:
加密算法
1.設要參與計算簽名的數據為集合 M,將集合 M 內非空參數值的參數按照參數名 ASCII 碼從小到大排序(字典序),使用 URL 鍵值對的格式(即key1=value1&key2=value2…)拼接成字符串 signTemp。
特別注意以下重要規則:
參數名 ASCII 碼從小到大排序(字典序)
如果參數的值為空不參與簽名
參數名區分大小寫
驗證調用返回或主動通知簽名時,傳送的 sign 參數不參與簽名,將生成的簽名與該 sign 值作校驗
接口可能增加字段,驗證簽名時必須支持增加的擴展字段
2.對 signTemp 進行 MD5 運算,再將得到的字符串所有字符轉換為大寫,得到 sign 值 signValue。
訪問過期時間
如果不限制簽名的使用時間,則生成的簽名永遠有效,如果別人拿到生成的鏈接后就能一直使用了,這是比較危險的,所以限制簽名時長很有必要,有 2 種方式可以限制簽名的有效時間:
1.客戶端加簽名生成時間:
- 生成簽名時的時間加入計算簽名
- 服務器收到請求后:簽名有效 並且 服務器當前時間 <= 參數中的時間 + 過期時長 則放行訪問,否則拒絕訪問
n 如果客戶端的時間或則服務器端的時間不准,就有可能簽名會無效,例如客戶端的時間是 2016 年的,而服務器端的是 2017 年的,簽名的過期時長為 5 分鍾,則計算的簽名就會是無效的。反過來簽名的有效時間就變長了。
n 還有個辦法,使用服務器時間進行簽名:在計算簽名前先向服務器請求一下服務器的時間,然后用此時間進行簽名即可。服務器接收到請求時判斷一下這個時間一定要比服務器當前時間早才行。
2.服務器記錄簽名時間:
- 客戶端計算簽名(不使用時間)
- 服務器收到請求后:
n 如果簽名有效且是第一次使用,則保存簽名和時間 T1 到數據庫或則 Redis 等,放行訪問
n 如果簽名不是第一次訪問(能從數據庫或則 Redis 中查找到),並且 服務器當前時間 <= T1 + 過期時長 則放行訪問,否則拒絕訪問
優點:此種方式是最安全的。
缺點:服務器端需要一直保存簽名,否則刪除后再次使用時就變成第一次使用了,不過 Redis 之類的存儲幾億條記錄訪問還是很快的。
二. Cookie-Session認證
由於http協議是無狀態的,所以基於http協議進行的認證,都需要依賴客戶端上傳的某種標識
基於 Cookie-Session 身份驗證機制的過程
- 用戶輸入登錄信息
- 服務端驗證登錄信息是否正確,如果正確就在服務器端為這個用戶創建一個 Session,並把 Session 存入數據庫
- 服務器端會向客戶端返回帶有 sessionID 的 Cookie
- 客戶端接收到服務器端發來的請求之后,看見響應頭中的 Set-Cookie 字段,將 Cookie 保存起來
- 接下來的請求中都會帶上這個 Cookie,服務器將 sessionID 和 數據庫中的相匹配,如果有效則處理該請求
- 如果用戶登出,Session 會在客戶端和服務器端都被銷毀
Cookie-Session認證的問題
- 擴展性不好,當擁有多台服務器的情況下,如何共享 Session 會成為一個問題,也就是說,用戶第一個訪問的時候是服務器 A,而第二個請求被轉發給了服務器 B,那服務器 B 無法得知其狀態。(舉例來說,A 網站和 B 網站是同一家公司的關聯服務。用戶只要在其中一個網站登錄,再訪問另一個網站自動登錄)
- 安全性不好,攻擊者可以利用本地 Cookie 進行欺騙和 CSRF 攻擊。
- Session 保存在服務器端,如果短時間內有大量用戶,會影響服務器性能。
- 跨域問題,Cookie 屬於同源策略限制的內容之一。
三. OAuth
OAuth分為OAuth1和OAuth2,目前OAuth2.0是OAuth協議的延續版本,但不向后兼容OAuth 1.0即完全廢止了OAuth1.0。
應用場景是第三方應用授權登錄:在APP或者網頁接入一些第三方應用時,時長會需要用戶登錄另一個合作平台,比如QQ,微博,微信的授權登錄。
OAuth2.0本質上就是將這里的客戶應用向授權服務器請求令牌與授權服務器頒發令牌的過程標准化了,根據這樣一套標准與解決方案,我們就可以安全的讓第三方應用訪問存儲在我們服務器上的用戶數據了。
OAuth2.0是用於REST/APIs的代理授權框架(delegated authorization framework),它基於令牌Token的授權,在無需暴露用戶密碼的情況下,使應用能獲取對用戶數據的有限訪問權限。
OAuth2.0客戶端獲取授權的四種模式 (具體可以參考6)
l 授權碼模式(authorization code)
l 簡化模式(implicit)
l 密碼模式(resource owner password credentials)
l 客戶端模式(client credentials)
結合自己的項目文檔:OAuth2.0總結.note
四. JWT
JWTs(JSON Web Tokens)JWT是一種無狀態的鑒權機制。將用戶登錄后的一些信息(比如用戶Id)和過期時間等信息存儲在一個加密過的字符串中,當服務器收到請求的時候,進行解密並直接使用信息。可以理解JWT是對於Token的一種規范。
Token 相對於 Cookie + Session 的優點,主要有下面兩個:
CSRF 攻擊
這個原理不多做介紹,構成這個攻擊的原因,就在於 Cookie + Session 的鑒權方式中,鑒權數據(cookie 中的 session_id)是由瀏覽器自動攜帶發送到服務端的,借助這個特性,攻擊者就可以通過讓用戶誤點攻擊鏈接,達到攻擊效果。而 token 是通過客戶端本身邏輯作為動態參數加到請求中的,token 也不會輕易泄露出去,因此 token 在 CSRF 防御方面存在天然優勢。
適合移動應用
移動端上不支持 cookie,而 token 只要客戶端能夠進行存儲就能夠使用,因此 token 在移動端上也具有優勢。
JWT 組成:
一個 JWT token 是一個字符串,它由三部分組成,頭部(header)、載荷(Payload:通常也被稱作實際數據或者數據體。)與簽名(Signature),中間用 . 分隔,例如:xxxxx.yyyyy.zzzzz
①頭部通常由兩部分組成:令牌的類型(即 JWT)和正在使用的簽名算法(如 HMAC SHA256 或 RSA.)。
{ "alg": "HS256", "typ": "JWT" }
然后用 Base64Url 編碼得到頭部,即 xxxxx。
②載荷中放置了 token 的一些基本信息,以幫助接受它的服務器來理解這個 token。同時還可以包含一些自定義的信息,用戶信息交換。
載荷的屬性也分三類:
l 預定義的載荷(Registered)
{ "sub": "1", --主題(subject) "iss": "http://localhost:8000/auth/login", --簽發人(issuer) "iat": 1451888119, --簽發時間(Issued At) "exp": 1454516119, --過期時間(expiration time) "nbf": 1451888119, --生效時間,在此之前是無效的(Not Before) "jti": "37c107e4609ddbcc9c096ea5ee76c667", --編號(JWT ID) "aud": "dev" --受眾(audience) }
l 公有的載荷(public)
在使用 JWT 時可以額外定義的載荷。為了避免沖突,應該使用 IANA JSON Web Token Registry 中定義好的,或者給額外載荷加上類似命名空間的唯一標識。
l 私有的載荷(private)
在信息交互的雙方之間約定好的,既不是預定義載荷也不是公有載荷的一類載荷。這一類載荷可能會發生沖突,所以應該謹慎使用。
將上面的 json 進行 Base64Url 編碼得到載荷,即 yyyyy
③ 簽名
簽名時需要用到前面編碼過的兩個字符串,如果以 HMACSHA256 加密,就如下:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret )
加密后再進行 base64url 編碼最后得到的字符串就是 token 的第三部分 zzzzz。
組合便可以得到 token:xxxxx.yyyyy.zzzzz。
備注:
HMAC(Hash-based Message Authentication Code) 算法是不可逆算法,類似 MD5 和 hash ,但多一個密鑰,密鑰(即上面的 secret)由服務端持有,客戶端把 token 發給服務端后,服務端可以把其中的頭部和載荷再加上事先共享的 secret 再進行一次 HMAC 加密,得到的結果和 token 的第三段進行對比,如果一樣則表明數據沒有被篡改。
JWT 的使用有兩種方式:
l 加到 url 中:?token=你的token
l 加到 header 中,建議用這種,因為在 https 情況下更安全:Authorization:Bearer 你的token
參考:
1權限管理控制與RBAC模型 https://blog.csdn.net/MyArray/article/details/81129777
2WebAPI常見的鑒權方法,及其適用范圍 https://www.cnblogs.com/mrbug/p/8027918.html
3cookie-session機制與JWT機制對比 https://www.jianshu.com/p/cbe253281d26
4淺談 Cookie-Session 、Jwt 兩種身份認證機制 https://juejin.im/post/5d567e09e51d453c12504dfc
5OAuth2介紹與使用 https://baijiahao.baidu.com/s?id=1620083471706505859&wfr=spider&for=pc
6理解OAuth 2.0http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
7CSRF攻擊和XSS攻擊 https://www.jianshu.com/p/4a0e151876ad
8CSRF攻擊的應對之道 https://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/
9JWT 超詳細分析 https://learnku.com/articles/17883#58ac43