Yahoo! ID連携

ID Token

ID Tokenとは

ID Tokenとはユーザー認証情報を含む改ざん検知用の署名付きTokenであり、JWT(JSON Web Token)フォーマットでエンコードされています。Yahoo! ID連携では、JWTの署名生成アルゴリズムとしてRSA-SHA256を採用しています。

Yahoo! ID連携を利用するクライアントでYahoo! JAPAN IDをベースにユーザー認証を行う場合は、Access TokenやRefresh Tokenではなく必ずID Tokenに含まれる認証情報を元にユーザーセッション管理を行ってください。

JWTの詳細な仕様については以下をご参照ください。


ID Tokenを構成するパラメーター

JWTはピリオド(".")区切りのHeader、Payload、Signatureから構成されます。

各部位はBase64URLエンコードされています。Base64エンコードはURLのパラメーターとして付与した際に"+"、"/"、"="などURLとして予約されている文字列が含まれるため、URL-Safe(URLに含めることが可能)なエンコードとしてBase64URLエンコードが用いられています。

Header

署名のアルゴリズムなどJWTを取り扱うために必要なパラメーターが含まれます。

パラメーター 必須 説明 値のサンプル
typ ID Tokenフォーマットのタイプ(固定値) "JWT"
alg 署名のアルゴリズム
RS256:RSA-SHA256
"RS256"
kid 署名検証に用いる公開鍵のKey ID
JWKsエンドポイントのJSON Web Key Setのkid、またはPublic KeysエンドポイントのPublic Keyのキー名に一致します。
"0cc175b9c0f1b6a831c399e269772661"

サンプル

{
  "typ": "JWT",
  "alg": "RS256",
  "kid": "0cc175b9c0f1b6a831c399e269772661"
}

Payload

ユーザー識別子や認証時刻などユーザーの認証情報のパラメーターが含まれます。

パラメーター 必須 説明 値のサンプル
issID Tokenの発行元(固定値)"https://auth.login.yahoo.co.jp/yconnect/v2"
subユーザー識別子(26Byte固定長)"KVNE5DZLWIY4Y57TRDLURJOOEU"
audID Tokenの発行対象のClient IDの配列(1つのClient IDは最大255Byteの可変長文字列)["dj0zaiZpPWxCUTczV01KazczNSZzPWNvbnN
1bWVyc2VjcmV0Jng9NDc-"]
expID Tokenの有効期限のUNIXタイムスタンプ1453618036
iatID Tokenの発行時刻のUNIXタイムスタンプ1453272436
auth_timeYahoo! JAPANのログイン画面における認証時刻のUNIXタイムスタンプ
※Authorizationエンドポイントのリクエスト時にmax_ageパラメーターを指定していない場合は含まれません。
1453271436
nonceAuthorizationエンドポイントのリクエスト時にnonceパラメーターに指定した値
リプレイアタック対策に用いられます
※nonceパラメーターを指定していない場合は含まれません。
"n-0S6_WzA2Mj"
amrYahoo! JAPANのログイン画面における認証時の認証手段の配列
  • pwd:パスワード認証
  • otp:パスワード認証かつワンタイムパスワード認証
  • sms:SMS認証
  • email:メール認証
※ 一部認証手段を含まない場合があります。
["pwd"]
at_hashAccess Tokenのハッシュ値
Access TokenをID TokenのSignature生成時と同じハッシュアルゴリズム(SHA256)でハッシュ化し、オクテッドの前部をBase64URLエンコードした文字列
※Authorizationエンドポイントのリクエスト時のresponse_typeパラメーターに""code""または""code id_token token""を指定する(ID TokenとAccess Tokenを同意時に発行する)場合に含まれます。
"SjjfaAWSdWEvSDfASCmonm"
c_hashAuthorization Codeのハッシュ値
Authorization CodeをID TokenのSignature生成時と同じハッシュアルゴリズム(SHA256)でハッシュ化し、オクテッドの前部をBase64URLエンコードした文字列
※Authorizationエンドポイントのリクエスト時のresponse_typeパラメーターに"code id_token"または"code id_token token"を指定する(ID TokenとAuthorization Codeを同意時に発行する)場合に含まれます。
"LDktKdoQak3Pk0cnXxCltA"

サンプル

{
  "iss": "https://auth.login.yahoo.co.jp/yconnect/v2",
  "sub": "KVNE5DZLWIY4Y57TRDLURJOOEU",
  "aud": ["dj0zaiZpPWxCUTczV01KazczNSZzPWNvbnN1bWVyc2VjcmV0Jng9NDc-"],
  "exp": 1453618036,
  "iat": 1453272436,
  "auth_time": 1453271436,
  "nonce": "n-0S6_WzA2Mj",
  "amr": ["pwd"],
  "at_hash": "SjjfaAWSdWEvSDfASCmonm",
  "c_hash": "LDktKdoQak3Pk0cnXxCltA"
}

Signature

HeaderとPayloadから生成された改ざん防止のための署名です。

Base64URLエンコードされたHeader + "." + Payloadを入力値としてRSA-SHA256で署名した結果をBase64URLエンコードした文字列です。



ID Tokenの検証手順

ID Tokenを用いた認証を行う場合は、以下の手順を参考に検証を行ってください。JWT対応のライブラリーを用いる場合は各ライブラリーに従って適宜必要な処理を行ってください。

  1. Authorizationエンドポイントのリクエスト時に指定するnonce値をデータベースやセッションなどに保存します。nonce値の衝突の可能性を低くするため保存期間は短く設定することを推奨します。この保存期間は後述のiat値の検証で用います。
  2. 取得したJWTをピリオド(".")で区切りHeader、Payload、Signatureの3つに分割します。
    • 前部:Header
    • 中部:Payload
    • 後部:Signature
  3. 取得したID TokenをBase64URLデコードします。
    Base64URLデコードの例(PHP)
    function base64UrlDecode($data)
    {
        $replaced = str_replace(array('-', '_'), array('+', '/'), $data);
        $lack = strlen($replaced) % 4;
        if ($lack > 0) {
            $replaced .= str_repeat("=", 4 - $lack);
        }
        return base64_decode($replaced);
    }
    
  4. Headerに含まれるkid値を用いて、JWKsエンドポイントまたはPublic Keysエンドポイントからkid値(またはキー名)から対になるPublic Keyを取得します。
  5. Headerに含まれるalg値を用いて、署名アルゴリズムを確認します。(現在、Yahoo! ID連携 v2はRSA-SHA256のみのサポートであるためこの処理は省略可能です)
  6. 入力値はBase64URLエンコード状態のままのHeader + "." + Payload、アルゴリズムはRSA-SHA256とし、取得したPublic Keyを用いて正しい署名であることを検証します。
  7. Public Keysエンドポイントから取得したPublic Keyを用いた署名検証の例(PHP)
    function verifySignature($header, $payload, $signature, $publicKey)
    {
        $data = $header . '.' . $payload;
        $decodedSignature = base64UrlDecode($signature);
        $publicKeyId = openssl_pkey_get_public($publicKey);
        if (!$publicKeyId) {
            // failed to get public key resource
            return false;
        }
        $result = openssl_verify($data, $decodedSignature, $publicKeyId, 'RSA-SHA256');
        openssl_free_key($publicKeyId);
        if ($result !== 1) {
            // invalid signature
            return false;
        }
        return true;
    }
    
  8. ID Tokenの発行元の改ざんを防ぐために、Payloadのiss値がOpenID Configurationエンドポイントのレスポンスに含まれるiss値("https://auth.login.yahoo.co.jp/yconnect/v2")と完全一致していることを検証します。
  9. 対象のウェブサイトやアプリケーションと異なるサービスに発行されたID Tokenでないことを確認するために、Payloadのaud値に対象のウェブサイトやアプリケーションに発行されたClient IDの値が含まれていることを検証します。
  10. ID Tokenを受け取るアプリケーションへのリプレイアタック(有効なID Tokenなどのクレデンシャルを繰り返し送信し不正アクセスなどを行う攻撃)を防止するため、Payloadのnonce値が保存していたAuthorizationエンドポイントのリクエスト時に指定した値と一致していることを検証します。検証済みのnonce値はデータベースやセッションなどから破棄します。
  11. Access TokenとID Tokenを同時に発行する場合には、Access Tokenの置き換え攻撃(対象のユーザーの異なるユーザーのクレデンシャルを置き換えて不正アクセスなどを行う攻撃)を防ぐために、Access TokenをHeaderのalgと同じハッシュアルゴリズム(SHA256)でハッシュ化し、オクテッドの前部をBase64URLエンコードした文字列とPayloadのat_hash値が一致していることを検証します。
  12. ハッシュ値生成の例(PHP)
    function generateHash($value)
    {
        $hash = hash('sha256', $value, true);
        $length = strlen($hash) / 2;
        $halfOfHash = substr($hash, 0, $length);
        return $this->urlsafeBase64Encode($halfOfHash);
    }
    
  13. Authorization CodeとID Tokenを同時に発行する場合には、Authorization Codeの置き換え攻撃(対象のユーザーの異なるユーザーのクレデンシャルを置き換えて不正アクセスなどを行う攻撃)を防ぐために、Authorization CodeをHeaderのalgと同じハッシュアルゴリズム(SHA256)でハッシュ化し、オクテッドの前部をBase64URLエンコードした文字列とPayloadのc_hash値が一致していることを検証します。(ハッシュ値生成は前述と同様)
  14. ID Tokenの有効期限を確認するために、Payloadのexp値が検証時のUNIXタイムスタンプの値よりも大きいことを検証します。
  15. Payloadのiat値が"(検証時のUNIXタイムスタンプ値)-(600秒)"の値以上であることを検証します。この手順では600秒としていますが、nonceを保存してからID Tokenを対象のサービスが受け取るまでの所要時間を目安として、サービスのポリシーで所要時間を決めてください。 クライアントサイドアプリケーションではエンドユーザーが端末側の時刻設定を手動で現在時刻と異なる時刻に設定している場合があるため、サーバーから返却される現在時刻を比較対象のタイムスタンプとして利用することを推奨します。
  16. 一定期間内にYahoo! JAPANのログイン画面における認証を要求する場合には、Payloadのauth_time値を用いて認証時刻を検証してください。

  • 6~11の手順において検証に失敗する場合は、ID Tokenが改ざんされている可能性があるため認証処理を中断し、エラー処理などを行ってください。

  • 12~14の手順において検証に失敗する場合は、有効期限切れや認証時刻が過ぎているため認証処理を中断し、再度ID Token取得のフローを行ってください。

  • 上記の検証がすべて正しく行えた場合のみ対象のサービスを認証とし、必要に応じて各パラメーターの値を利用してください。

  • 認証後のウェブサイトやアプリケーションのセッションはサービスのポリシーに従い有効期限を設定してください。Payloadのexp値はYahoo! JAPANが発行するID Tokenの有効期限です。サービスの有効期限は必ずしもexp値に従う必要はありません。

  • Payloadのsub値はユーザーを識別する場合に必要に応じて参照してください。

  • Payloadのamr値は認証判定の要素として認証手段を用いる場合に必要に応じて参照してください。

  • ID Tokenの詳細な検証手順については以下をご参照ください。



Yahoo!知恵袋で調べる