OIDC協(xié)議
OIDC(OpenID Connect)是在OAuth2上構(gòu)建了一個(gè)身份層示弓,是一個(gè)基于OAuth2協(xié)議的身份認(rèn)證標(biāo)準(zhǔn)協(xié)議打毛。
OAuth2協(xié)議
OAuth2是一個(gè)授權(quán)協(xié)議,它無法提供完善的身份認(rèn)證功能【1】导坟,OIDC使用OAuth2的授權(quán)服務(wù)器來為第三方客戶端提供用戶的身份認(rèn)證魔种,并把對應(yīng)的身份認(rèn)證信息傳遞給客戶端擎勘。
使用OAuth2進(jìn)行認(rèn)證的常見誤區(qū)
如果用OAuth2進(jìn)行認(rèn)證,會有許多問題刀崖。
- 在OAuth2中惊科,
token
被設(shè)計(jì)成是對客戶端
不透明的,但在用戶身份認(rèn)證的上下文環(huán)境中,客戶端
往往需要能夠從token
中派生一些信息蒲跨。這可以通過定義一個(gè)雙重目的(dual-purposing)的客戶端
以解析和理解的token
來完成译断。但是OAuth2協(xié)議并沒有為access token
本身定義特定的格式貨結(jié)構(gòu),因此需要在OAuth2協(xié)議的基礎(chǔ)上或悲,利用諸如OpenId Connect的ID Token
在響應(yīng)中提供一個(gè)次要的標(biāo)記孙咪,它將和access token
一起發(fā)送給客戶端
中。一方面巡语,保持了token
是對客戶端
的不透明翎蹈,另一方面,為客戶端
提供了其所需的認(rèn)證信息男公。 - OAuth保護(hù)的是資源荤堪,獲取用戶屬性的API(identity API)通常沒有辦法告訴你用戶是否存在。而且枢赔,在某些情況下澄阳,用戶無需身份驗(yàn)證即可獲得access token(比如[認(rèn)證授權(quán)] 1.OAuth2授權(quán) - 5.4 Client Credentials Grant)。也就是說
Access Token
并不能和某個(gè)用戶
關(guān)聯(lián)起來踏拜。 - 在某些場合碎赢,例如,使用implicit流程(這個(gè)流程中直接把a(bǔ)cces token作為url的hash參數(shù)([認(rèn)證授權(quán)] 1.OAuth2 授權(quán) - 5.2.2 Access Token Response))中速梗,
User Agent
可以獲得token
肮塞,也就你開辟了一個(gè)注入access token
到應(yīng)用程序外部(并可能在應(yīng)用程序外部泄露)的地方襟齿。如果Client不通過某種機(jī)制驗(yàn)證access token,則它無法區(qū)分access token是有效的令牌還是攻擊的令牌枕赵。 - 很可能有一個(gè)幼稚的(naive)
客戶端
猜欺,從其他的客戶端
拿到一個(gè)有效的token
來作為自己的登錄事件。畢竟token
是有效的拷窜,對API的訪問也會返回有效的用戶
信息开皿。問題在于沒有用戶做任何事情來證明用戶
存在,在這種情況下装黑,用戶
甚至都沒有授權(quán)給幼稚的(naive)客戶端
副瀑。 - 如果攻擊者能夠攔截或者替換來自Client的一個(gè)調(diào)用,它可能會改變返回的用戶信息恋谭,而客戶端卻無法感知這一情況糠睡。這將允許攻擊者通過簡單地在正確的調(diào)用序列中交換用戶標(biāo)識符來模擬一個(gè)幼稚的(naive)Client上的用戶。
- 基于OAuth 身份(identity)API的最大問題在于疚颊,即使使用完全符合OAuth的機(jī)制狈孔,不同的提供程序不可避免的會使用不同的方式實(shí)現(xiàn)身份(identity)API。
OIDC核心概念:ID Token
OAuth2提供了Access Token
來解決授權(quán)第三方客戶端
訪問受保護(hù)資源的問題材义;OIDC在這個(gè)基礎(chǔ)上提供了ID Token
來解決第三方客戶端標(biāo)識用戶身份認(rèn)證的問題均抽。OIDC的核心在于在OAuth2的授權(quán)流程中,一并提供用戶的身份認(rèn)證信息(ID Token
)給到第三方客戶端
其掂,ID Token
使用JWT
格式來包裝油挥。此外還提供了UserInfo的
接口,用戶獲取用戶的更完整的信息款熬。
參與角色
主要的術(shù)語以及概念介紹:
- EU:End User:一個(gè)人類
用戶
深寥。 - RP:Relying Party ,用來代指OAuth2中的受信任的
客戶端
,身份認(rèn)證和授權(quán)信息的消費(fèi)方贤牛; - OP:OpenID Provider惋鹅,有能力提供EU認(rèn)證的服務(wù)(比如OAuth2中的授權(quán)服務(wù)),用來為RP提供EU的身份認(rèn)證信息殉簸;
- ID Token:JWT格式的數(shù)據(jù)闰集,包含EU身份認(rèn)證的信息。
- UserInfo Endpoint:用戶信息接口(受OAuth2保護(hù))般卑,當(dāng)RP使用
Access Token
訪問時(shí)武鲁,返回授權(quán)用戶的信息,此接口必須使用HTTPS蝠检。
工作流程
OIDC的流程由以下5個(gè)步驟構(gòu)成:
-
RP
發(fā)送一個(gè)認(rèn)證請求給OP
洞坑; -
OP
對EU
進(jìn)行身份認(rèn)證,然后提供授權(quán)蝇率; -
OP
把ID Token
和Access Token
(需要的話)返回給RP
迟杂; -
RP
使用Access Token
發(fā)送一個(gè)請求UserInfo EndPoint
; -
UserInfo EndPoint
返回EU
的Claims
本慕。
注意這里面RP
發(fā)往OP
的請求排拷,是屬于Authentication
類型的請求,雖然在OIDC中是復(fù)用OAuth2的Authorization
請求通道锅尘,但是用途是不一樣的监氢,且OIDC的AuthN請求中scope參數(shù)必須要有一個(gè)值為的openid
的參數(shù),用來區(qū)分這是一個(gè)OIDC的Authentication
請求藤违,而不是OAuth2的Authorization
請求浪腐。
什么是ID Token
OIDC對OAuth2最主要的擴(kuò)展就是提供了ID Token
。ID Token
是一個(gè)安全令牌
顿乒,是一個(gè)授權(quán)服務(wù)器
提供的包含用戶信息(由一組Cliams構(gòu)成以及其他輔助的Cliams)的JWT
格式的數(shù)據(jù)結(jié)構(gòu)议街。
另外ID Token
必須使用JWS進(jìn)行簽名和JWE加密,從而提供認(rèn)證的完整性璧榄、不可否認(rèn)性以及可選的保密性特漩。一個(gè)ID Token
的例子如下:
1 {
2 "iss": "https://server.example.com",
3 "sub": "24400320",
4 "aud": "s6BhdRkqt3",
5 "nonce": "n-0S6_WzA2Mj",
6 "exp": 1311281970,
7 "iat": 1311280970,
8 "auth_time": 1311280969,
9 "acr": "urn:mace:incommon:iap:silver"
10 }
如何獲取ID Token
因?yàn)镺IDC基于OAuth2,所以O(shè)IDC的認(rèn)證流程主要是由OAuth2的幾種授權(quán)流程延伸而來的骨杂,有以下3種:
- Authorization Code Flow:使用OAuth2的授權(quán)碼來換取
Id Token
和Access Token
涂身。 - Implicit Flow:使用OAuth2的Implicit流程獲取
Id Token
和Access Token
。 - Hybrid Flow:混合Authorization Code Flow+Implici Flow搓蚪。
Resource Owner Password Credentials Grant是需要用途提供賬號密碼給RP的蛤售,賬號密碼給到RP了,就不再需要ID Token了妒潭。
Client Credentials Grant這種方式根本就不需要用戶參與悴能,更談不上用戶身份認(rèn)證了。這也能反映授權(quán)和認(rèn)證的差異杜耙,以及只使用OAuth2來做身份認(rèn)證的事情是遠(yuǎn)遠(yuǎn)不夠的搜骡,也是不合適的。
這里主要介紹基于Authorization Code的認(rèn)證請求/答復(fù)佑女。
基于Authorization Code的認(rèn)證請求的請求
所有的Token
都是通過Token EndPoint
來發(fā)放的记靡。構(gòu)建一個(gè)OIDC的Authentication Request需要提供如下的參數(shù):
- scope:必須。OIDC的請求必須包含值為
openid
的scope的參數(shù)团驱。 - response_type:必選摸吠。同OAuth2。
- client_id:必選嚎花。同OAuth2寸痢。
- redirect_uri:必選。同OAuth2紊选。
- state:推薦啼止。同OAuth2道逗。防止CSRF, XSRF。
以上這5個(gè)參數(shù)是和OAuth2相同的献烦。除此之外滓窍,還定義了一些參數(shù)【2】例如:
- response_mode:可選。OIDC新定義的參數(shù)巩那,用來指定Authorization Endpoint以何種方式返回?cái)?shù)據(jù)吏夯。
一個(gè)簡單的示例如下:
GET /authorize?
response_type=code
&scope=openid%20profile%20email
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb HTTP/1.1
Host: server.example.com
基于Authorization Code的認(rèn)證請求的響應(yīng)
在授權(quán)服務(wù)器
接收到認(rèn)證請求之后,需要對請求參數(shù)做嚴(yán)格的驗(yàn)證即横。驗(yàn)證通過后引導(dǎo)EU
進(jìn)行身份認(rèn)證并且同意授權(quán)噪生。在這一切都完成后,會重定向到RP
指定的回調(diào)地址东囚,并且把code
和state
參數(shù)傳遞過去跺嗽。比如:
HTTP/1.1 302 Found
Location: https://client.example.org/cb?
code=SplxlOBeZQQYbYS6WxSbIA
&state=af0ifjsldkj
獲取ID Token
RP
使用上一步獲得的code
來請求Token EndPoint
,這一步同OAuth2舔庶。然后Token EndPoint
會返回響應(yīng)的Token
抛蚁,其中除了OAuth2規(guī)定的部分?jǐn)?shù)據(jù)外,還會附加一個(gè)id_token
的字段惕橙。id_token
字段就是上面提到的ID Token
瞧甩。例如:
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token": "SlAV32hkKG",
"token_type": "Bearer",
"refresh_token": "8xLOxBtZp8",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc
yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5
NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ
fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz
AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q
Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ
NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd
QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS
K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4
XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg"
}
其中看起來一堆亂碼的部分就是JWT
格式的ID Token
。在RP
拿到這些信息之后弥鹦,需要對id_token
以及access_token
進(jìn)行驗(yàn)證肚逸。至此,可以說用戶身份認(rèn)證就可以完成了彬坏,后續(xù)可以根據(jù)UserInfo EndPoint
獲取更完整的信息朦促。
OIDC協(xié)議簇
除了Core核心規(guī)范內(nèi)容多一點(diǎn)之外,另外7個(gè)都是很簡單且簡短的規(guī)范栓始,另外Core是基于OAuth2的务冕,也就是說其中很多東西在復(fù)用OAuth2。
OpenId Connect定義了一個(gè)發(fā)現(xiàn)協(xié)議幻赚,它允許Client輕松的獲取有關(guān)如何和特定的身份認(rèn)證提供者進(jìn)行交互的信息禀忆。在另一方面,還定義了一個(gè)Client注冊協(xié)議落恼,允許Client引入新的身份提供程序(identity providers)箩退。通過這兩種機(jī)制和一個(gè)通用的身份API,OpenId Connect可以運(yùn)行在互聯(lián)網(wǎng)規(guī)模上運(yùn)行良好佳谦,在那里沒有任何一方事先知道對方的存在戴涝。
UserInfo Endpoint
UserIndo EndPoint
是一個(gè)受OAuth2保護(hù)的資源。在RP
得到Access Token
后可以請求此資源,然后獲得一組EU
相關(guān)的Claims
啥刻,這些信息可以說是ID Token
的擴(kuò)展奸鸯,
GET /userinfo HTTP/1.1
Host: server.example.com
Authorization: Bearer SlAV32hkKG
成功之后相應(yīng)如下:
HTTP/1.1 200 OK
Content-Type: application/json
{
"sub": "248289761001",
"name": "Jane Doe",
"given_name": "Jane",
"family_name": "Doe",
"preferred_username": "j.doe",
"email": "janedoe@example.com",
"picture": "http://example.com/janedoe/me.jpg"
}
【1】OAuth2中的access_token
【2】[認(rèn)證 & 授權(quán)] 4. OIDC(OpenId Connect)身份認(rèn)證(核心部分)