ライセンス トークンを使用してサービスのライセンスを検証する
Microsoft Game Development Kit (GDK) ランタイム内のライセンス トークンによって、実行中のアプリの有効なライセンスをクライアントが持っていることをゲーム サービスで検証する手段が提供されます。クライアントを信頼する必要はありません。 これらのトークンは、PC 上で実行されているアプリのライセンスを検証するためのものです。Xbox アプリには不要です。
ライセンス トークンは JSON Web Token (JWT) 形式です。使用可能な JWT ハンドラーを使用してアンパックできます。 検証テストでは、http://jwt.io で JWT デコード ツールにライセンス トークンを入力できます。
ライセンス トークンには、次の表に示すセクションがあります。
セクション | 説明 |
---|---|
ヘッダー | トークンの検証に使用する適切な証明書を決定するために使用される x5t を提供します。 |
ペイロード |
LicenseTokenClaim 値に base64 エンコード文字列が含まれており、クライアントからのライセンスに関する追加情報を提供します。
LicenseToken の有効期限も提供します。 |
署名 | トークンの整合性とソースを検証する標準 JWT 署名。 検証用に Microsoft からダウンロードされた署名証明書の公的証明書を使用します。 |
クライアントからライセンス トークンを取得する
ライセンス トークンを取得するには、クライアントは XStoreQueryLicenseTokenAsync API 呼び出す必要があります。これには、製品のストア ID およびカスタム開発者の文字列が渡されます。詳細については、このトピックの後半で説明します。 この API は、Microsoft Store アプリに現在サインインしているユーザーに基づき、アプリのライセンス トークンを取得します。 開発サンドボックスを使用している場合、テスト アカウントは、Xbox Windows アプリと Microsoft Store アプリの両方にサインインする必要があります。 トークンが取得されると、自身のサービスに送信され、検証されます。 サービスに対してクライアントから送信された結果の信頼性が無効になるため、ライセンス トークンをクライアントで検証することはできません。
ライセンス トークンを取得する方法の例については、「ゲーム内ストアのサンプル」をご覧ください。
サービスのライセンス トークンを検証する
ライセンス トークンを処理する方法の完全なコード例については、「ゲーム サービスのサンプル」をご覧ください。
トークンの署名に使用された証明書から RSA 公開キーを取得する必要があります。
証明書をダウンロードするフル URL を決定するには、次のいずれかの方法で certificateId
を決定する必要があります。
- base64 エンコードされたペイロード内の
certificateId
値を抽出します。 - ヘッダーの x5t 値をバイト配列に Base64 デコードして、文字列に変換します。 これを行う方法のコード例は、ゲームサービスのサンプルに用意されています。
-
certificateId
を取得したら、デコードした文字列でこの値を取り出して、https://licensing.mp.microsoft.com/v8.0/licenseToken/fullCertificate/{certificateId}
に追加し、証明書の直接ダウンロード リンクを取得します。
X509Certificate2 などの証明書オブジェクトを作成するために使用できる未加工の証明書データを含む XML ドキュメントが作成されます (コード例については、「ゲームサービスのサンプル」をご覧ください)。 この証明書をキャッシュし、ライセンス トークンを検証するたびにダウンロードする必要がないようにする必要があります。
証明書の RSA 公開鍵があれば、標準 JWT 署名の検証を使用して、ライセンス トークンが信頼できる発行元からのものであり、トークンの内容が変更されていないことを確認できます。
ライセンス トークン内の情報を使用する
ライセンス トークンのペイロードには、追加の JSON データの base64 エンコード文字列である LicenseTokenClaim
値が含まれています。
文字列の先頭部分はデコード後に無視できるため、最初の "{" を探して JSON データの先頭を示します。
これを次の例に示します。
[Unicode character string that can be ignored]
{
"certificateId": "C4FC9E583CC4D5FEB96712619B5BE7499FECB5FA",
"customDeveloperString": "anti-replay string",
"licensableProducts": [
{
"endDate": "9999-12-31T23:59:59.9999999+00:00",
"isShared": false,
"id": "fc80277459b04bc7a158b49c0c5574e1",
"productId": "9NN4ZHKML55R",
"skuId": "0010",
"userId": "m8jGdShdpG8vu9nIQiAn3lBIQJ+TD0r2jAJvfmGYmGI="
}
],
"payload": "T3Jqb3H+YHkjgBksJcsBaL6noHabm5JfyCYaV9nnV+XTiAzNfHKCdUqK2KZkZNk7aYfsVJ0CL2mFQg8XdYtxOv+YmHi+6qhXv6Wp5mx3e4+ZFavbobwjPbVgVsKpDV3TxKdUCIhVPPtDOziqWsUB3+z4plopXM+SargAqqBchQOQklRf5z4NXkAqWer31MmZWwXeEcsfH7Ac/usMlrQakT1IepxnR7+bZIKzp7B9QcWN2lJzyP4TYg8gVnYBGT9cRWxy/IgY0gL5FYNLnDJM1A3D2JcmsCsKuCVpzzn2eXdSAGha00oqBdCcQMr34da54x1s47lvZTdP+Z4Z/BjSQw==",
"tokenVersion": 1
}
クライアントが製品の有効なライセンスを持っている場合、licensableProducts
リストの結果として返されます。
endDate
値は UTC 時間で表され、payload
文字列は今後の使用のために予約されています。
customDeveloperString パラメーターを使用して再生攻撃を防ぐ
クライアントはサービスへの有効なトークンの送信を傍受して、その有効なトークンを再生することができるため、XStoreQueryLicenseToken
API の customDeveloperString
パラメーターを適切に使用することが重要です。
この文字列はサーバー上で生成し、各ライセンス チェック固有にする必要があります。
文字列は、生成後にクライアントに送信されます。その後、クライアントはこの文字列を XStoreQueryLicenseToken
API に渡します。
この値はライセンス トークンのペイロードに埋め込まれ、 トークンの検証署名によって変更されないように保護されます。
クライアントがトークンをサービスに送信した後、customDeveloperString
値がサーバーが生成し、クライアントに送信した値と完全に一致することを確認できます。
この値が一致しない場合、トークンのその他のすべての側面がまだ有効であるため、サービスをだまそうとして以前のトークンを再生していることを示している可能性があります。
実行するライセンス チェックごとにランダムな文字列または GUID を customDeveloperString
に使用することをお勧めします。