Rest API的認(rèn)證模式
微服務(wù)系統(tǒng)中,很多團(tuán)隊(duì)采用了API驅(qū)動設(shè)計(jì)開發(fā),服務(wù)之間的調(diào)用都通過API來實(shí)現(xiàn)的。為了統(tǒng)一管理API,一般都會在前面部署一個API Gateway,然后由API Gateway對API的調(diào)用者進(jìn)行權(quán)限認(rèn)證。 常見的認(rèn)證方式有下面幾種:
- AppKey
- AppKey + Secret
- JWT
- OAuth
下面我們逐一來介紹這些App的認(rèn)證方式,以及對應(yīng)的使用場景.
AppKey
AppKey 是比較悠久,也是比較簡單但是蠻有效的一種方式方法。當(dāng)Application申請?jiān)L問API后,API Gateway會為這個Application生成一個AppKey,一般是UUID等隨機(jī)無意義的字符串。當(dāng)Application調(diào)用API的時候,需要在Http Header或者是Query里面帶上這個AppKey, 然后API Gateway進(jìn)行校驗(yàn),驗(yàn)證無誤后方可訪問到具體的API。 比如
GET http://api.example.com/users?AppKey=1234567890abcdef
或者是在header里面:
GET http://api.example.com/users
x-app-key=1234567890abcdef
不建議放在Query里面,這樣很容易就被爆出來,因?yàn)榧词故荋TTPS連接,URL也是不會加密的。同時建議用RFC7235關(guān)于HTTP認(rèn)證部分的標(biāo)準(zhǔn),以Authorization header的方式進(jìn)行連接:
GET http://api.example.com/users?AppKey=1234567890abcdef
Authorization: AppKey 1234567890abcdef
小結(jié):AppKey簡單明了,帶著key直接就可以走了!如果只是為了能識別API的調(diào)用者,同時進(jìn)行一些常規(guī)的API Gateway邏輯,AppKey也就夠了。其實(shí)微軟Azure API Management里面的subscription 就是直接用AppKey作為Header進(jìn)行訪問的。
AppKey + Secret
我們知道Hash算法可以能夠完成密碼學(xué)四大目標(biāo)之一的完整性檢驗(yàn),但是不能避免消息被篡改:比如有人將內(nèi)容以及Hash一起給改掉。為了避免消息被篡改,偉大的前人設(shè)計(jì)出消息驗(yàn)證碼(Message Authentication Code), 在計(jì)算hash的時候,同時在里面加入密鑰,得出基于Hash的消息驗(yàn)證碼,常見的有HMAC (Hash-based Message Authentication Code).
現(xiàn)在我們要介紹的這種API的認(rèn)證方式同時帶上AppKey以及消息驗(yàn)證碼的。當(dāng)Application申請?jiān)L問API后,API Gateway會為這個Application生成一對Key, 一個叫AppKey,另一個叫App Secret。 API Gateway保存這對Key/Secret. 當(dāng)Application發(fā)起請求時,首先是在header帶上這個AppKey,然后按照API Gateway的要求,對請求的URL, body, header等消息進(jìn)行HMAC運(yùn)算,并作為HTTP Header發(fā)送,最終發(fā)給服務(wù)器的內(nèi)容大致如下:
POST ttp://api.example.com/users
Authorization: AppKey 1234567890abcdef
X-Ca-Signature: HMAC(HTTP Method+Headers+Body)
Body content
當(dāng)API Gateway收到這個請求之后,它會取出這個AppKey對應(yīng)的AppSecret,然后以相同的算法對請求的內(nèi)容進(jìn)行HMAC運(yùn)算,將得出的摘要跟發(fā)過來的摘要比較。這里的摘要也有些地方叫 簽名。
小結(jié):這種方式雖然稍微復(fù)雜了點(diǎn),但同時把身份確認(rèn)以及消息不被篡改的要求都滿足了。阿里云API Gateway的subscription就是采用這種方式。
JWT
如果AppKey泄露或者被截取,竊取方在Application發(fā)現(xiàn)AppKey泄露之前,是可以用Application的不受限地進(jìn)行API的調(diào)用。那怎樣才能最低程度地減少AppKey丟失之后的風(fēng)險(xiǎn)呢? 比如有效期縮短?
Json Web Token(縮寫JWT) 是目前比較流行的跨域身份認(rèn)證解決方案。以令牌的方式進(jìn)行溝通,而令牌自身帶著身份信息,并且具有時效性,過期無效。所以我們可以采用JWT來減少AppKey丟失之后的風(fēng)險(xiǎn)。
一個JWT包括3個部分:頭部(算法以及類型),Payload(具體的內(nèi)容,主要是有效時間,名字等) 以及簽名。格式為 aaaa.bbbbb.cccc. 每一部分的內(nèi)容都用Base64編碼進(jìn)行表示。

- 首先Application在API Gateway注冊的時候,API Gateway會返回一對ID/Secret。
- 在Application調(diào)用API之前,先帶上ID、Secret去調(diào)用API Gateway的Token接口,API Gateway 返回令牌
- Application 把token放在Authorization header里面,去請求API
- API Gateway驗(yàn)證JWT是否過期,簽名是否合法,以及Payload里面的信息,如果合法就允許繼續(xù)訪問
如果Token別人截取了,那么竊取方只能在token過期之前這個時間段內(nèi) 假扮成Application去調(diào)用API。
小結(jié):JWT會使得口令丟失的損失減低一些,同時payload里面可以帶更多的有用的信息(當(dāng)然標(biāo)準(zhǔn)規(guī)范里面的payload也沒有多少可定制的字段),可以進(jìn)行一些相應(yīng)的權(quán)限或者業(yè)務(wù)操作。
OAuth
OAuth是一個可以為第三方應(yīng)用訪問用戶資源的安全框架。OAuth有4種不同的認(rèn)證授權(quán):
- 授權(quán)碼模式 - Authorization Code
- 客戶端憑據(jù) - Client Credentials
- 密碼模式 - Password
- 隱式授權(quán) - Implicit
授權(quán)碼模式跟隱式授權(quán)模式都是在有用戶的場景下使用 (隱式授權(quán)模式?jīng)]有授權(quán)碼,而是直接獲得access token),而密碼模式則是直接要用戶輸入用戶名密碼的,一般都不用??蛻舳藨{據(jù) Client Credential 這種方式可以用來作為API 的認(rèn)證授權(quán)。
具體的操作流程跟JWT的方式下類似:
首先Application在API Gateway注冊的時候,API Gateway會返回一對client Id / Secret。
在Application調(diào)用API之前,先帶上client Id / Secret去調(diào)用API Gateway的Access Token接口,API Gateway 返回Access Token.
Application 把Access Token放在header里面,
Authorization: Bearer ACCESS_TOKEN去請求APIAPI Gateway驗(yàn)證Access Token是否過期,簽名是否合法,解開payload,檢查是否該令牌是否有權(quán)限訪問該資源,如果驗(yàn)證通過 則允許繼續(xù)訪問
小結(jié): API Gateway 的龍頭老大Google Apigee就是采用OAuth Client Credentials的方式進(jìn)行Application的認(rèn)證授權(quán)的,微軟Azure的API Management除了上面說的subscription的方式,也支持了AAD OAuth的方式,不過過程比較繁瑣。如果API Gateway除了需要身份認(rèn)證之外,還需要進(jìn)行權(quán)限的校驗(yàn),那么以JWT作為Access Token的OAuth是一種值得一試的方案。