HTTP API 認證授權(quán)術(shù)

轉(zhuǎn)自 https://coolshell.cn/articles/19395.html

我們知道,HTTP是無狀態(tài)的,所以,當我們需要獲得用戶是否在登錄的狀態(tài)時,我們需要檢查用戶的登錄狀態(tài),一般來說,用戶的登錄成功后,服務(wù)器會發(fā)一個登錄憑證(又被叫作Token),就像你去訪問某個公司,在前臺被認證過合法后,這個公司的前臺會給你的一個訪客卡一樣,之后,你在這個公司內(nèi)去到哪都用這個訪客卡來開門,而不再校驗?zāi)闶悄囊粋€人。在計算機的世界里,這個登錄憑證的相關(guān)數(shù)據(jù)會放在兩種地方,一個地方在用戶端,以Cookie的方式(一般不會放在瀏覽器的Local Storage,因為這很容易出現(xiàn)登錄憑證被XSS攻擊),另一個地方是放在服務(wù)器端,又叫Session的方式(SessonID存于Cookie)。

但是,這個世界還是比較復(fù)雜的,除了用戶訪問,還有用戶委托的第三方的應(yīng)用,還有企業(yè)和企業(yè)間的調(diào)用,這里,我想把業(yè)內(nèi)常用的一些 API認證技術(shù)相對系統(tǒng)地總結(jié)歸納一下,這樣可以讓大家更為全面的了解這些技術(shù)。注意,這是一篇長文!

本篇文章會覆蓋如下技術(shù):

HTTP Basic
Digest Access
App Secret Key + HMAC
JWT – JSON Web Tokens
OAuth 1.0 – 3 legged & 2 legged
OAuth 2.0 – Authentication Code & Client Credential

目錄

<nav style="box-sizing: border-box; display: block; color: rgb(66, 66, 66); font-family: "Source Sans Pro", sans-serif; font-size: 18px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: justify; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">

</nav>

HTTP Basic

HTTP Basic 是一個非常傳統(tǒng)的API認證技術(shù),也是一個比較簡單的技術(shù)。這個技術(shù)也就是使用 usernamepassword 來進行登錄。整個過程被定義在了 RFC 2617 中,也被描述在了 Wikipedia: Basic Access Authentication 詞條中,同時也可以參看 MDN HTTP Authentication

其技術(shù)原理如下:

  1. usernamepassword 做成 username:password 的樣子(用冒號分隔)
  2. 進行Base64編碼。Base64("username:password") 得到一個字符串(如:把 haoel:coolshell 進行base64 后可以得到 aGFvZW86Y29vbHNoZWxsCg
  3. aGFvZW86Y29vbHNoZWxsCg放到HTTP頭中 Authorization 字段中,形成 Authorization: Basic aGFvZW86Y29vbHNoZWxsCg,然后發(fā)送到服務(wù)端。
  4. 服務(wù)端如果沒有在頭里看到認證字段,則返回401錯,以及一個個[WWW-Authenticate](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate): Basic Realm='HelloWorld' 之類的頭要求客戶端進行認證。之后如果沒有認證通過,則返回一個401錯。如果服務(wù)端認證通過,那么會返回200。

我們可以看到,使用Base64的目的無非就是為了把一些特殊的字符給搞掉,這樣就可以放在HTTP協(xié)議里傳輸了。而這種方式的問題最大的問題就是把用戶名和口令放在網(wǎng)絡(luò)上傳,所以,一般要配合TLS/SSL的安全加密方式來使用。我們可以看到 JIRA Cloud 的API認證支持HTTP Basic 這樣的方式。

但我們還是要知道,這種把用戶名和密碼同時放在公網(wǎng)上傳輸?shù)姆绞接悬c不太好,因為Base64不是加密協(xié)議,而是編碼協(xié)議,所以就算是有HTTPS作為安全保護,給人的感覺還是不放心。

Digest Access

中文稱“HTTP 摘要認證”,最初被定義在了 RFC 2069 文檔中(后來被 RFC 2617 引入了一系列安全增強的選項;“保護質(zhì)量”(qop)、隨機數(shù)計數(shù)器由客戶端增加、以及客戶生成的隨機數(shù))。

其基本思路是,請求方把用戶名口令和域做一個MD5 – MD5(username:realm:password) 然后傳給服務(wù)器,這樣就不會在網(wǎng)上傳用戶名和口令了,但是,因為用戶名和口令基本不會變,所以,這個MD5的字符串也是比較固定的,因此,這個認證過程在其中加入了兩個事,一個是 nonce 另一個是 qop

  • 首先,調(diào)用方發(fā)起一個普通的HTTP請求。比如:GET /coolshell/admin/ HTTP/1.1
  • 服務(wù)端自然不能認證能過,服務(wù)端返回401錯誤,并且在HTTP頭里的 WWW-Authenticate 包含如下信息:

WWW-Authenticate: Digest realm="testrealm@host.com",
qop="auth,auth-int",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
opaque="5ccc069c403ebaf9f0171e9517f40e41"</pre>

  • 其中的 nonce 為服務(wù)器端生成的隨機數(shù),然后,客戶端做 HASH1=MD5(MD5(username:realm:password):nonce:cnonce) ,其中的 cnonce 為客戶端生成的隨機數(shù),這樣就可以使得整個MD5的結(jié)果是不一樣的。
  • 如果 qop 中包含了 auth ,那么還得做 HASH2=MD5(method:digestURI) 其中的 method 就是HTTP的請求方法(GET/POST…),digestURI 是請求的URL。
  • 如果 qop 中包含了 auth-init ,那么,得做 HASH2=MD5(method:digestURI:MD5(entityBody)) 其中的 entityBody 就是HTTP請求的整個數(shù)據(jù)體。
  • 然后,得到 response = MD5(HASH1:nonce:nonceCount:cnonce:qop:HASH2) 如果沒有 qopresponse = MD5(HA1:nonce:HA2)
  • 最后,我們的客戶端對服務(wù)端發(fā)起如下請求—— 注意HTTP頭的 Authorization: Digest ...

GET /dir/index.html HTTP/1.0
Host: localhost
Authorization: Digest username="Mufasa",
realm="testrealm@host.com",
nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",
uri="%2Fcoolshell%2Fadmin",
qop=auth,
nc=00000001,
cnonce="0a4f113b",
response="6629fae49393a05397450978507c4ef1",
opaque="5ccc069c403ebaf9f0171e9517f40e41"</pre>

維基百科上的 Wikipedia: Digest access authentication 詞條非常詳細地描述了這個細節(jié)。

摘要認證這個方式會比之前的方式要好一些,因為沒有在網(wǎng)上傳遞用戶的密碼,而只是把密碼的MD5傳送過去,相對會比較安全,而且,其并不需要是否TLS/SSL的安全鏈接。但是,別看這個算法這么復(fù)雜,最后你可以發(fā)現(xiàn),整個過程其實關(guān)鍵是用戶的password,這個password如果不夠得雜,其實是可以被暴力破解的,而且,整個過程是非常容易受到中間人攻擊——比如一個中間人告訴客戶端需要的 Basic 的認證方式 或是 老舊簽名認證方式(RFC2069)。

App Secret Key + HMAC

先說HMAC技術(shù),這個東西來自于MAC – Message Authentication Code,是一種用于給消息簽名的技術(shù),也就是說,我們怕消息在傳遞的過程中被人修改,所以,我們需要用對消息進行一個MAC算法,得到一個摘要字串,然后,接收方得到消息后,進行同樣的計算,然后比較這個MAC字符串,如果一致,則表明沒有被修改過(整個過程參看下圖)。而HMAC – Hash-based Authenticsation Code,指的是利用Hash技術(shù)完成這一工作,比如:SHA-256算法。

image.png

(圖片來自 Wikipedia – MAC 詞條

我們再來說App ID,這個東西跟驗證沒有關(guān)系,只是用來區(qū)分,是誰來調(diào)用API的,就像我們每個人的身份證一樣,只是用來標注不同的人,不是用來做身份認證的。與前面的不同之處是,這里,我們需要用App ID 來映射一個用于加密的密鑰,這樣一來,我們就可以在服務(wù)器端進行相關(guān)的管理,我們可以生成若干個密鑰對(AppID, AppSecret),并可以有更細粒度的操作權(quán)限管理。

把AppID和HMAC用于API認證,目前來說,玩得最好最專業(yè)的應(yīng)該是AWS了,我們可以通過S3的API請求簽名文檔看到AWS是怎么玩的。整個過程還是非常復(fù)雜的,可以通過下面的圖片流程看個大概。基本上來說,分成如下幾個步驟:

  1. 把HTTP的請求(方法、URI、查詢字串、頭、簽名頭,body)打個包叫 CanonicalRequest,作個SHA-256的簽名,然后再做一個base16的編碼
  2. 把上面的這個簽名和簽名算法 AWS4-HMAC-SHA256、時間戳、Scop,再打一個包,叫 StringToSign
  3. 準備簽名,用 AWSSecretAccessKey來對日期簽一個 DataKey,再用 DataKey 對要操作的Region簽一個 DataRegionKey ,再對相關(guān)的服務(wù)簽一個DataRegionServiceKey ,最后得到 SigningKey.
  4. 用第三步的 SigningKey來對第二步的 StringToSign 簽名。
image.png

最后,發(fā)出HTTP Request時,在HTTP頭的 Authorization字段中放入如下的信息:

Authorization: AWS4-HMAC-SHA256
Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request,
SignedHeaders=content-type;host;x-amz-date,
Signature=5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7

其中的 AKIDEXAMPLE 是 AWS Access Key ID, 也就是所謂的 AppID,服務(wù)器端會根據(jù)這個AppID來查相關(guān)的 Secret Access Key,然后再驗證簽名。如果,你對這個過程有點沒看懂的話,你可以讀一讀這篇文章——《Amazon S3 Rest API with curl》這篇文章里有好些代碼,代碼應(yīng)該是最有細節(jié)也是最準確的了。

這種認證的方式好處在于,AppID和AppSecretKey,是由服務(wù)器的系統(tǒng)開出的,所以,是可以被管理的,AWS的IAM就是相關(guān)的管理,其管理了用戶、權(quán)限和其對應(yīng)的AppID和AppSecretKey。但是不好的地方在于,這個東西沒有標準 ,所以,各家的實現(xiàn)很不一致。比如: Acquia 的 HMAC微信的簽名算法 (這里,我們需要說明一下,微信的API沒有遵循HTTP協(xié)議的標準,把認證信息放在HTTP 頭的 Authorization 里,而是放在body里)

JWT – JSON Web Tokens

JWT是一個比較標準的認證解決方案,這個技術(shù)在Java圈里應(yīng)該用的是非常普遍的。JWT簽名也是一種MAC(Message Authentication Code)的方法。JWT的簽名流程一般是下面這個樣:

用戶使用用戶名和口令到認證服務(wù)器上請求認證。
認證服務(wù)器驗證用戶名和口令后,以服務(wù)器端生成JWT Token,這個token的生成過程如下:
認證服務(wù)器還會生成一個 Secret Key(密鑰)
對JWT Header和 JWT Payload分別求Base64。在Payload可能包括了用戶的抽象ID和的過期時間。
用密鑰對JWT簽名 HMAC-SHA256(SecertKey, Base64UrlEncode(JWT-Header)+'.'+Base64UrlEncode(JWT-Payload));
然后把 base64(header).base64(payload).signature 作為 JWT token返回客戶端。
客戶端使用JWT Token向應(yīng)用服務(wù)器發(fā)送相關(guān)的請求。這個JWT Token就像一個臨時用戶權(quán)證一樣。
當應(yīng)用服務(wù)器收到請求后:

  1. 應(yīng)用服務(wù)會檢查 JWT Token,確認簽名是正確的。
  2. 然而,因為只有認證服務(wù)器有這個用戶的Secret Key(密鑰),所以,應(yīng)用服務(wù)器得把JWT Token傳給認證服務(wù)器。
  3. 認證服務(wù)器通過JWT Payload 解出用戶的抽象ID,然后通過抽象ID查到登錄時生成的Secret Key,然后再來檢查一下簽名。
  4. 認證服務(wù)器檢查通過后,應(yīng)用服務(wù)就可以認為這是合法請求了。

我們可以看以,上面的這個過程,是在認證服務(wù)器上為用戶動態(tài)生成 Secret Key的,應(yīng)用服務(wù)在驗簽的時候,需要到認證服務(wù)器上去簽,這個過程增加了一些網(wǎng)絡(luò)調(diào)用,所以,JWT除了支持HMAC-SHA256的算法外,還支持RSA的非對稱加密的算法。

使用RSA非對稱算法,在認證服務(wù)器這邊放一個私鑰,在應(yīng)用服務(wù)器那邊放一個公鑰,認證服務(wù)器使用私鑰加密,應(yīng)用服務(wù)器使用公鑰解密,這樣一來,就不需要應(yīng)用服務(wù)器向認證服務(wù)器請求了,但是,RSA是一個很慢的算法,所以,雖然你省了網(wǎng)絡(luò)調(diào)用,但是卻費了CPU,尤其是Header和Payload比較長的時候。所以,一種比較好的玩法是,如果我們把header 和 payload簡單地做SHA256,這會很快,然后,我們用RSA加密這個SHA256出來的字符串,這樣一來,RSA算法就比較快了,而我們也做到了使用RSA簽名的目的。

最后,我們只需要使用一個機制在認證服務(wù)器和應(yīng)用服務(wù)器之間定期地換一下公鑰私鑰對就好了。

這里強烈建議全文閱讀 Anglar 大學(xué)的 《JSW:The Complete Guide to JSON Web Tokens

OAuth 1.0

OAuth也是一個API認證的協(xié)議,這個協(xié)議最初在2006年由Twitter的工程師在開發(fā)OpenID實現(xiàn)的時候和社交書簽網(wǎng)站Ma.gnolia時發(fā)現(xiàn),沒有一種好的委托授權(quán)協(xié)議,后來在2007年成立了一個OAuth小組,知道這個消息后,Google員工也加入進來,并完善有善了這個協(xié)議,在2007年底發(fā)布草案,過一年后,在2008年將OAuth放進了IETF作進一步的標準化工作,最后在2010年4月,正式發(fā)布OAuth 1.0,即:RFC 5849 (這個RFC比起TCP的那些來說讀起來還是很輕松的),不過,如果你想了解其前身的草案,可以讀一下 OAuth Core 1.0 Revision A ,我在下面做個大概的描述。

根據(jù)RFC 5849,可以看到 OAuth 的出現(xiàn),目的是為了,用戶為了想使用一個第三方的網(wǎng)絡(luò)打印服務(wù)來打印他在某網(wǎng)站上的照片,但是,用戶不想把自己的用戶名和口令交給那個第三方的網(wǎng)絡(luò)打印服務(wù),但又想讓那個第三方的網(wǎng)絡(luò)打印服務(wù)來訪問自己的照片,為了解決這個授權(quán)的問題,OAuth這個協(xié)議就出來了。

這個協(xié)議有三個角色:
User(照片所有者-用戶)
Consumer(第三方照片打印服務(wù))
Service Provider(照片存儲服務(wù))
這個協(xié)義有三個階段:
Consumer獲取Request Token
Service Provider 認證用戶并授權(quán)Consumer
Consumer獲取Access Token調(diào)用API訪問用戶的照片
整個授權(quán)過程是這樣的:

Consumer(第三方照片打印服務(wù))需要先上Service Provider獲得開發(fā)的 Consumer Key 和 Consumer Secret
當 User 訪問 Consumer 時,Consumer 向 Service Provide 發(fā)起請求請求Request Token (需要對HTTP請求簽名)
Service Provide 驗明 Consumer 是注冊過的第三方服務(wù)商后,返回 Request Token(oauth_token)和 Request Token Secret (oauth_token_secret)
Consumer 收到 Request Token 后,使用HTTP GET 請求把 User 切到 Service Provide 的認證頁上(其中帶上Request Token),讓用戶輸入他的用戶和口令。
Service Provider 認證 User 成功后,跳回 Consumer,并返回 Request Token (oauth_token)和 Verification Code(oauth_verifier)
接下來就是簽名請求,用Request Token 和 Verification Code 換取 Access Token (oauth_token)和 Access Token Secret (oauth_token_secret)
最后使用Access Token 訪問用戶授權(quán)訪問的資源。
下圖附上一個Yahoo!的流程圖可以看到整個過程的相關(guān)細節(jié)。


image.png

因為上面這個流程有三方:User,Consumer 和 Service Provide,所以,又叫 3-legged flow,三腳流程。OAuth 1.0 也有不需要用戶參與的,只有Consumer 和 Service Provider 的, 也就是 2-legged flow 兩腳流程,其中省掉了用戶認證的事。整個過程如下所示:

Consumer(第三方照片打印服務(wù))需要先上Service Provider獲得開發(fā)的 Consumer Key 和 Consumer Secret
Consumer 向 Service Provide 發(fā)起請求請求Request Token (需要對HTTP請求簽名)
Service Provide 驗明 Consumer 是注冊過的第三方服務(wù)商后,返回 Request Token(oauth_token)和 Request Token Secret (oauth_token_secret)
Consumer 收到 Request Token 后,直接換取 Access Token (oauth_token)和 Access Token Secret (oauth_token_secret)
最后使用Access Token 訪問用戶授權(quán)訪問的資源。
最后,再來說一說OAuth中的簽名。

我們可以看到,有兩個密鑰,一個是Consumer注冊Service Provider時由Provider頒發(fā)的 Consumer Secret,另一個是 Token Secret。
簽名密鑰就是由這兩具密鑰拼接而成的,其中用 &作連接符。假設(shè) Consumer Secret 為 j49sk3j29djd 而 Token Secret 為dh893hdasih9那個,簽名密鑰為:j49sk3j29djd&dh893hdasih9
在請求Request/Access Token的時候需要對整個HTTP請求進行簽名(使用HMAC-SHA1和HMAC-RSA1簽名算法),請求頭中需要包括一些OAuth需要的字段,如:
Consumer Key : 也就是所謂的AppID
Token: Request Token 或 Access Token
Signature Method :簽名算法比如:HMAC-SHA1
Timestamp:過期時間
Nonce:隨機字符串
Call Back:回調(diào)URL
下圖是整個簽名的示意圖:

圖片還是比較直觀的,我就不多解釋了。

OAuth 2.0

在前面,我們可以看到,從Digest Access, 到AppID+HMAC,再到JWT,再到OAuth 1.0,這些個API認證都是要向Client發(fā)一個密鑰(或是用密碼)然后用HASH或是RSA來簽HTTP的請求,這其中有個主要的原因是,以前的HTTP是明文傳輸,所以,在傳輸過程中很容易被篡改,于是才搞出來一套的安全簽名機制,所以,這些個認證的玩法是可以在HTTP明文協(xié)議下玩的。

這種使用簽名方式大家可以看到是比較復(fù)雜的,所以,對于開發(fā)者來說,也是很不友好的,在組織簽名的那些HTTP報文的時候,各種,URLEncode和Base64,還要對Query的參數(shù)進行排序,然后有的方法還要層層簽名,非常容易出錯,另外,這種認證的安全粒度比較粗,授權(quán)也比較單一,對于有終端用戶參與的移動端來說也有點不夠。所以,在2012年的時候,OAuth 2.0 的 RFC 6749 正式放出。

OAuth 2.0依賴于TLS/SSL的鏈路加密技術(shù)(HTTPS),完全放棄了簽名的方式,認證服務(wù)器再也不返回什么 token secret 的密鑰了,所以,OAuth 2.0是完全不同于1.0 的,也是不兼容的。目前,F(xiàn)acebook 的 Graph API 只支持OAuth 2.0協(xié)議,Google 和 Microsoft Azure 也支持Auth 2.0,國內(nèi)的微信和支付寶也支持使用OAuth 2.0。

下面,我們來重點看一下OAuth 2.0的兩個主要的Flow:

  • 一個是Authorization Code Flow, 這個是 3 legged 的
  • 一個是Client Credential Flow,這個是 2 legged 的。
Authorization Code Flow

Authorization Code 是最常使用的OAuth 2.0的授權(quán)許可類型,它適用于用戶給第三方應(yīng)用授權(quán)訪問自己信息的場景。這個Flow也是OAuth 2.0四個Flow中我個人覺得最完整的一個Flow,其流程圖如下所示。

image.png

下面是對這個流程的一個細節(jié)上的解釋:

1)當用戶(Resource Owner)訪問第三方應(yīng)用(Client)的時候,第三方應(yīng)用會把用戶帶到認證服務(wù)器(Authorization Server)上去,主要請求的是 /authorize API,其中的請求方式如下所示。

https://login.authorization-server.com/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&response_type=code
&redirect_uri=http%3A%2F%2Fexample-client.com%2Fcallback%2F
&scope=read
&state=xcoiv98CoolShell3kch

其中:

client_id為第三方應(yīng)用的App ID
response_type=code為告訴認證服務(wù)器,我要走Authorization Code Flow。
redirect_uri意思是我跳轉(zhuǎn)回第三方應(yīng)用的URL
scope意是相關(guān)的權(quán)限
state 是一個隨機的字符串,主要用于防CSRF攻擊。

2)當Authorization Server收到這個URL請求后,其會通過 client_id來檢查 redirect_uri和 scope是否合法,如果合法,則彈出一個頁面,讓用戶授權(quán)(如果用戶沒有登錄,則先讓用戶登錄,登錄完成后,出現(xiàn)授權(quán)訪問頁面)。

3)當用戶授權(quán)同意訪問以后,Authorization Server 會跳轉(zhuǎn)回 Client ,并以其中加入一個 Authorization Code。 如下所示:

https://example-client.com/callback?
code=Yzk5ZDczMzRlNDEwYlrEqdFSBzjqfTG
&state=xcoiv98CoolShell3kch
我們可以看到,

請流動的鏈接是第 1)步中的 redirect_uri
其中的 state 的值也和第 1)步的 state一樣。
4)接下來,Client 就可以使用 Authorization Code 獲得 Access Token。其需要向 Authorization Server 發(fā)出如下請求。

POST /oauth/token HTTP/1.1
Host: authorization-server.com
code=Yzk5ZDczMzRlNDEwYlrEqdFSBzjqfTG
&grant_type=code
&redirect_uri=https%3A%2F%2Fexample-client.com%2Fcallback%2F
&client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&client_secret=JqQX2PNo9bpM0uEihUPzyrh
5)如果沒什么問題,Authorization 會返回如下信息。

{
  "access_token": "iJKV1QiLCJhbGciOiJSUzI1NiI",
  "refresh_token": "1KaPlrEqdFSBzjqfTGAMxZGU",
  "token_type": "bearer",
  "expires": 3600,
  "id_token": "eyJ0eXAiOiJKV1QiLCJhbGciO.eyJhdWQiOiIyZDRkM..."
}

其中,
access_token就是訪問請求令牌了
refresh_token用于刷新 access_token
id_token 是JWT的token,其中一般會包含用戶的OpenID
6)接下來就是用 Access Token 請求用戶的資源了。

GET /v1/user/pictures
Host: https://example.resource.com

Authorization: Bearer iJKV1QiLCJhbGciOiJSUzI1NiI

Client Credential Flow
Client Credential 是一個簡化版的API認證,主要是用于認證服務(wù)器到服務(wù)器的調(diào)用,也就是沒有用戶參與的的認證流程。下面是相關(guān)的流程圖。

image.png

這個過程非常簡單,本質(zhì)上就是Client用自己的 client_id和 client_secret向Authorization Server 要一個 Access Token,然后使用Access Token訪問相關(guān)的資源。

請求示例

POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=czZCaGRSa3F0Mzpn
&client_secret=7Fjfp0ZBr1KtDRbnfVdmIw

返回示例

{
  "access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
  "token_type":"bearer",
  "expires_in":3600,
  "refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
  "scope":"create"
}

這里,容我多扯一句,微信公從平臺的開發(fā)文檔中,使用了OAuth 2.0 的 Client Credentials的方式(參看文檔“微信公眾號獲取access token”),我截了個圖如下所謂。我們可以看到,微信公眾號使用的是GET方式的請求,把AppID和AppSecret放在了URL中,雖然這也符合OAuth 2.0,但是并不好,因為大多數(shù)網(wǎng)關(guān)代理會把整個URI請求記到日志中。我們只要腦補一下騰訊的網(wǎng)關(guān)的Access Log,里面的日志一定會有很多的各個用戶的AppID和AppSecret……

image.png

小結(jié)
講了這么多,我們來小結(jié)一下(下面的小結(jié)可能會有點散)

兩個概念和三個術(shù)語
區(qū)分兩個概念:Authentication(認證) 和 Authorization (授權(quán)),前者是證明請求者是身份,就像身份證一樣,后者是為了獲得權(quán)限。身份是區(qū)別于別人的證明,而權(quán)限是證明自己的特權(quán)。Authentication為了證明操作的這個人就是他本人,需要提供密碼、短信驗證碼,甚至人臉識別。Authorization 則是不需要在所有的請求都需要驗人,是在經(jīng)過Authorization后得到一個Token,這就是Authorization。就像護照和簽證一樣。
區(qū)分三個概念:編碼Base64Encode、簽名HMAC、加密RSA。編碼是為了更的傳輸,等同于明文,簽名是為了信息不能被篡改,加密是為了不讓別人看到是什么信息。
明白一些初衷
使用復(fù)雜地HMAC哈希簽名方式主要是應(yīng)對當年沒有TLS/SSL加密鏈路的情況。
JWT把 uid 放在 Token中目的是為了去掉狀態(tài),但不能讓用戶修改,所以需要簽名。
OAuth 1.0區(qū)分了兩個事,一個是第三方的Client,一個是真正的用戶,其先拿Request Token,再換Access Token的方法主要是為了把第三方應(yīng)用和用戶區(qū)分開來。
用戶的Password是用戶自己設(shè)置的,復(fù)雜度不可控,服務(wù)端頒發(fā)的Serect會很復(fù)雜,但主要目的是為了容易管理,可以隨時注銷掉。
OAuth 協(xié)議有比所有認證協(xié)議有更為靈活完善的配置,如果使用AppID/AppSecret簽名的方式,又需要做到可以有不同的權(quán)限和可以隨時注銷,那么你得開發(fā)一個像AWS的IAM這樣的賬號和密鑰對管理的系統(tǒng)。
相關(guān)的注意事項
無論是哪種方式,我們都應(yīng)該遵循HTTP的規(guī)范,把認證信息放在 Authorization HTTP 頭中。
不要使用GET的方式在URL中放入secret之類的東西,因為很多proxy或gateway的軟件會把整個URL記在Access Log文件中。
密鑰Secret相當于Password,但他是用來加密的,最好不要在網(wǎng)絡(luò)上傳輸,如果要傳輸,最好使用TLS/SSL的安全鏈路。
HMAC中無論是MD5還是SHA1/SHA2,其計算都是非常快的,RSA的非對稱加密是比較耗CPU的,尤其是要加密的字符串很長的時候。
最好不要在程序中hard code 你的 Secret,因為在github上有很多黑客的軟件在監(jiān)視各種Secret,千萬小心!這類的東西應(yīng)該放在你的配置系統(tǒng)或是部署系統(tǒng)中,在程序啟動時設(shè)置在配置文件或是環(huán)境變量中。
使用AppID/AppSecret,還是使用OAuth1.0a,還是OAuth2.0,還是使用JWT,我個人建議使用TLS/SSL下的OAuth 2.0。
密鑰是需要被管理的,管理就是可以新增可以撤銷,可以設(shè)置賬戶和相關(guān)的權(quán)限。最好密鑰是可以被自動更換的。
認證授權(quán)服務(wù)器(Authorization Server)和應(yīng)用服務(wù)器(App Server)最好分開。
(全文完)
轉(zhuǎn)自 https://coolshell.cn/articles/19395.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372