來源:不止思考
應用程式的訪問安全又是我們每一個研發團隊都必須關注的重點問題。尤其是在我們採用了微服務架構之後,項目的複雜度提升了N個級別,相應的,微服務的安全工作也就更難更複雜了。並且我們以往擅長的單體應用的安全方案對於微服務來說已經不再適用了。我們必須有一套新的方案來保障微服務架構的安全。
在探索微服務訪問安全之前,我們還是先來回顧一下單體應用的安全是如何實現的。
一、傳統單體應用如何實現「訪問安全」?
下圖就是一個傳統單體應用的訪問示意圖:
(圖片來自WillTran在slideshare分享)
在應用伺服器裡面,我們有一個auth模塊(一般採用過濾來實現),當有客戶端請求進來時,所有的請求都必須首先經過這個auth來做身份驗證,驗證通過後,才將請求發到後面的業務邏輯。
通常客戶端在第一次請求的時候會帶上身份校驗信息(用戶名和密碼),auth模塊在驗證信息無誤後,就會返回Cookie存到客戶端,之後每次客戶端只需要在請求中攜帶Cookie來訪問,而auth模塊也只需要校驗Cookie的合法性後決定是否放行。
可見,在傳統單體應用中的安全架構還是蠻簡單的,對外也只有一個入口,通過auth校驗後,內部的用戶信息都是內存/線程傳遞,邏輯並不是複雜,所以風險也在可控範圍內。
那麼,當我們的項目改為微服務之後,「訪問安全」又該怎麼做呢。
二、微服務如何實現「訪問安全」?
在微服務架構下,有以下三種方案可以選擇,當然,用的最多的肯定還是OAuth模式。
- 網關鑒權模式(API Gateway)
- 服務自主鑒權模式
- API Token模式(OAuth2.0)
下面分別來講一下這三種模式:
- 網關鑒權模式(API Gateway)
- (圖片來自WillTran在slideshare分享)
- 通過上圖可見,因為在微服務的最前端一般會有一個API網關模塊(API Gateway),所有的外部請求訪問微服務集群時,都會首先通過這個API Gateway,所以我們可以在這個模塊里部署auth邏輯,實現統一集中鑒權,鑒權通過後,再把請求轉發給後端各個服務。
- 這種模式的優點就是,由API Gateway集中處理了鑒權的邏輯,使得後端各微服務節點自身邏輯就簡單了,只需要關注業務邏輯,無需關注安全性事宜。
- 這個模式的問題就是,API Gateway適用於身份驗證和簡單的路徑授權(基於URL的),對於複雜數據/角色的授權訪問權限,通過API Gateway很難去靈活的控制,畢竟這些邏輯都是存在後端服務上的,並非存儲在API Gateway里。
- 服務自主鑒權模式
- (圖片來自WillTran在slideshare分享)
- 服務自主鑒權就是指不通過前端的API Gateway來控制,而是由後端的每一個微服務節點自己去鑒權。
- 它的優點就是可以由更為靈活的訪問授權策略,並且相當於微服務節點完全無狀態化了。同時還可以避免API Gateway 中 auth 模塊的性能瓶頸。
- 缺點就是由於每一個微服務都自主鑒權,當一個請求要經過多個微服務節點時,會進行重複鑒權,增加了很多額外的性能開銷。
- API Token模式(OAuth2.0)
- (圖片來自網絡)
- 如圖,這是一種採用基於令牌Token的授權方式。在這個模式下,是由授權伺服器(圖中Authorization Server)、API網關(圖中API Gateway)、內部的微服務節點幾個模塊組成。
- 流程如下:
- 第一步:客戶端應用首先使用帳號密碼或者其它身份信息去訪問授權伺服器(Authorization Server)獲取 訪問令牌(Access Token)。
- 第二步:拿到訪問令牌(Access Token)後帶著它再去訪問API網關(圖中API Gateway),API Gateway自己是無法判斷這個Access Token是否合法的,所以走第三步。
- 第三步:API Gateway去調用Authorization Server校驗一下Access Token的合法性。
- 第四步:如果驗證完Access Token是合法的,那API Gateway就將Access Token換成JWT令牌返回。
- (注意:此處也可以不換成JWT而是直接返回原Access Token。但是換成JWT更好,因為Access Token是一串不可讀無意義的字符串,每次驗證Access Token是否合法都需要去訪問Authorization Server才知道。但是JWT令牌是一個包含JOSN對象,有用戶信息和其它數據的一個字符串,後面微服務節點拿到JWT之後,自己就可以做校驗,減少了交互次數)。
- 第五步:API Gateway有了JWT之後,就將請求向後端微服務節點進行轉發,同時會帶上這個JWT。
- 第六步:微服務節點收到請求後,讀取裡面的JWT,然後通過加密算法驗證這個JWT,驗證通過後,就處理請求邏輯。
- 這裡面就使用到了OAuth2.0的原理,不過這只是OAuth2.0各類模式中的一種。
由於OAuth2.0目前最為常用,所以接下來我再來詳細講解一下OAuth2.0的原理和各類用法。
三、詳解 OAuth2.0 的「 訪問安全 」?
OAuth2.0是一種訪問授權協議框架。它是基於Token令牌的授權方式,在不暴露用戶密碼的情況下,使 應用方 能夠獲取到用戶數據的訪問權限。
例如:你開發了一個視頻網站,可以採用第三方微信登陸,那麼只要用戶在微信上對這個網站授權了,那這個網站就可以在無需用戶密碼的情況下獲取用戶在微信上的頭像。
OAuth2.0 的流程如下圖:
OAuth2.0 里的主要名詞有:
- 資源伺服器:用戶數據/資源存放的地方,在微服務架構中,服務就是資源伺服器。在上面的例子中,微信頭像存放的服務就是資源伺服器。
- 資源擁有者:是指用戶,資源的擁有人。在上面的例子中某個微信頭像的用戶就是資源擁有者。
- 授權伺服器:是一個用來驗證用戶身份並頒發令牌的伺服器。
- 客戶端應用:想要訪問用戶受保護資源的客戶端/Web應用。在上面的例子中的視頻網站就是客戶端應用。
- 訪問令牌:Access Token,授予對資源伺服器的訪問權限額度令牌。
- 刷新令牌:客戶端應用用於獲取新的 Access Token 的一種令牌。
- 客戶憑證:用戶的帳號密碼,用於在 授權伺服器 進行驗證用戶身份的憑證。
OAuth2.0有四種授權模式,也就是四種獲取令牌的方式:授權碼、簡化式、用戶名密碼、客戶端憑證。
下面來分別講解一下:
- 授權碼(Authorization Code)
- 授權碼模式是指:客戶端應用先去申請一個授權碼,然後再拿著這個授權碼去獲取令牌的模式。這也是目前最為常用的一種模式,安全性比較高,適用於我們常用的前後端分離項目。通過前端跳轉的方式去訪問 授權伺服器 獲取授權碼,然後後端再用這個授權碼訪問 授權伺服器 以獲取 訪問令牌。
- 流程如上圖。
- 第一步,客戶端的前端頁面(圖中UserAgent)將用戶跳轉到 授權伺服器(Authorization Server)里進行授權,授權完成後,返回 授權碼(Authorization Code)
- 第二步,客戶端的後端服務(圖中Client)攜帶授權碼(Authorization Code)去訪問 授權伺服器,然後獲得正式的 訪問令牌(Access Token)
- 頁面的前端和後端分別做不同的邏輯,前端接觸不到Access Token,保證了Access Token的安全性。
- 簡化式(Implicit)
- 簡化模式是在項目是一個純前端應用,在沒有後端的情況下,採用的一種模式。
- 因為這種方式令牌是直接存在前端的,所以非常不安全,因此令牌的有限期設置就不能太長。
- 其流程就是:
- 第一步:應用(純前端的應用)將用戶跳轉到 授權伺服器(Authorization Server)里進行授權,授權完成後,授權伺服器 直接將 Access Token 返回給 前端應用,令牌存儲在前端頁面。
- 第二步:應用(純前端的應用)攜帶 訪問令牌(Access Token) 去訪問資源,獲取資源。
- 在整個過程中,雖然令牌是在前端URL中直接傳遞,但注意,令牌在HTTP協議中不是放在URL參數欄位中的,而是放在URL錨點裡。因為錨點數據不會被瀏覽器發到伺服器,因此有一定的安全保障。
- 用戶名密碼(Resource Owner Credentials)
- 這種方式最容易理解了,直接使用用戶的用戶名/密碼作為授權方式去訪問 授權伺服器,從而獲取Access Token,這個方式因為需要用戶給出自己的密碼,所以非常的不安全性。一般僅在客戶端應用與授權伺服器、資源伺服器是歸屬統一公司/團隊,互相非常信任的情況下採用。
- 客戶端憑證(Client Credentials)
- 這是適用於伺服器間通信的場景。客戶端應用拿一個用戶憑證去找授權伺服器獲取Access Token。
以上,就是對微服務架構中「訪問安全」的一些思考。
end:如果你覺得本文對你有幫助的話,記得點贊轉發,你的支持就是我更新動力。