- Demonstrating Proof-of-Possession at the Application Layer (DPoP)について個人用にメモする。
概要
- アクセストークン漏洩による不正なアクセストークン利用に対するセキュリティ向上策
- ①トークリクエスト/レスポンスと②アクセストークンを用いたリソースアクセス時に次の処理を行う。
①トークンリクエスト/レスポンス
クライアント側
-
HTTPヘッダー
DPoP
にDPoP Proof
を付与して、トークンリクエストを行う。 -
リクエスト例
POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded;charset=UTF-8 DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6IkVDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCRnMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JEQSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiItQndDM0VTYzZhY2MybFRjIiwiaHRtIjoiUE9TVCIsImh0dSI6Imh0dHBzOi8vc2VydmVyLmV4YW1wbGUuY29tL3Rva2VuIiwiaWF0IjoxNTYyMjYyNjE2fQ.2-GxA6T8lP4vfrg8v-FdWP0A0zdrj8igiMLvqRMUvwnQg4PtFLbdLXiOSsX0x7NVY-FNyJK70nfbV37xRZT3Lg grant_type=authorization_code &code=SplxlOBeZQQYbYS6WxSbIA &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb &code_verifier=bEaL42izcC-o-xBk0K2vuJ6U-y1p9r_wW2dFWIWgjz-
-
DPoP Proof
:クライアント側で生成した署名情報を含むJWT。- 署名鍵(公開鍵、秘密鍵)を生成する。
- 下記形式のヘッダー、ペイロードを用意する。
- 2を秘密鍵で署名し、JWTとする。
-
形式
{ "typ":"dpop+jwt", "alg":"ES256", "jwk": { "kty":"EC", "x":"l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs", "y":"9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA", "crv":"P-256" } } . { "jti":"-BwC3ESc6acc2lTc", "htm":"POST", "htu":"https://server.example.com/token", "iat":1562262616 }
-
ヘッダー部
クレーム 説明 typ
必須。 dpop+jwt
を指定する。alg
必須。署名アルゴリズムを指定する。 jwk
必須。クライアントが指定した公開鍵情報。 -
ペイロード部
クレーム 説明 jti
必須。一意な識別子を指定する。 htm
必須。HTTP メソッドを指定する。※トークンリクエストに対応 htu
必須。リクエストの URLを指定する。※トークンリクエストに対応 iat
必須。JWT 発行日時を指定する。
-
認可サーバー
-
トークンリクエストに指定された
DPoP Proof
から公開鍵を取り出し、署名検証を行う。- クライアントが秘密鍵を保持していることを確認。
-
アクセストークンを生成し、公開鍵と紐づける。
-
トークンレスポンスを返却する。
-
レスポンス例
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
{
"access_token": "Kz~8mXK1EalYznwH-LC-1fBAo.4Ljp~zsPE_NeO.gxU",
"token_type": "DPoP",
"expires_in": 2677,
"refresh_token": "Q..Zkm29lexi8VnWg2zPW1x-tgGad0Ibc3s3EwM_Ni4-g"
}
②リソースリクエスト・レスポンス
クライアント側
-
DPoP Proof
を生成し、②で取得したアクセストークンと併せてAPIコール時に指定する。-
DPoP Proof
-
①で生成した公開鍵を含む JSON と、API コールに対応するペイロードを作成
-
秘密鍵で署名し、JWTとする。
-
-
GET /protectedresource HTTP/1.1
Host: resource.example.org
Authorization: DPoP Kz~8mXK1EalYznwH-LC-1fBAo.4Ljp~zsPE_NeO.gxU
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6Ik
VDIiwieCI6Imw4dEZyaHgtMzR0VjNoUklDUkRZOXpDa0RscEJoRjQyVVFVZldWQVdCR
nMiLCJ5IjoiOVZFNGpmX09rX282NHpiVFRsY3VOSmFqSG10NnY5VERWclUwQ2R2R1JE
QSIsImNydiI6IlAtMjU2In19.eyJqdGkiOiJlMWozVl9iS2ljOC1MQUVCIiwiaHRtIj
oiR0VUIiwiaHR1IjoiaHR0cHM6Ly9yZXNvdXJjZS5leGFtcGxlLm9yZy9wcm90ZWN0Z
WRyZXNvdXJjZSIsImlhdCI6MTU2MjI2MjYxOCwiYXRoIjoiZlVIeU8ycjJaM0RaNTNF
c05yV0JiMHhXWG9hTnk1OUlpS0NBcWtzbVFFbyJ9.2oW9RP35yRqzhrtNP86L-Ey71E
OptxRimPPToA1plemAgR6pxHF8y6-yqyVnmcw6Fy1dqd-jfxSYoMxhAJpLjA
DPoP Proof形式
{
"typ":"dpop+jwt",
"alg":"ES256",
"jwk": {
"kty":"EC",
"x":"l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs",
"y":"9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA",
"crv":"P-256"
}
}
.
{
"jti":"e1j3V_bKic8-LAEB",
"htm":"GET",
"htu":"https://resource.example.org/protectedresource",
"iat":1562262618,
"ath":"fUHyO2r2Z3DZ53EsNrWBb0xWXoaNy59IiKCAqksmQEo"
}
リソースサーバー側
-
DPoP proof JWT
に含まれる公開鍵を用いて、署名を検証する。- クライアントが公開鍵に対応する秘密鍵を保持していることを確認する。
-
DPoP proof JWT
に含まれる公開鍵と②でアクセストークンに紐付づけた公開鍵が同一か確認する。- 同一である場合:API コールを許可
- 同一でない場合: API コールを拒否