レシート検証によって、ユーザーが購入していないコンテンツにアクセスすることを防ぎます。
レシートはアプリケーションのコンテンツを配布する時点で検証するのが最も効率的です。
重要: Unity IAP はローカルな検証方法を提供していますが、ローカルな検証は不正に対してより脆弱です。可能であれば、機密性の高いトランザクションをサーバーサイドで検証することがベストプラクティスと考えられます。詳細については、Apple および Android の不正防止に関するドキュメントを参照してください。
ユーザーが購入するコンテンツがすでにデバイスに存在する場合は、アプリケーションはただ、それをアンロックするかどうかを決定するだけです。
Unity IAP はコンテンツを隠し、Google Play と App Store をとおしてレシートを検証し分析するツールを提供します。
レシート検証は、アプリケーションの Google Play 公開キーや Apple のルート証明書などの既知の暗号化キーを使用して実行されます。
攻撃者がこれらの機密情報を置き換えることができると、レシート検証は失敗してしまいます。そのため、攻撃者が簡単にこれらのキーを見つけ、改変できないようにすることが大切です。
Unity IAP はアプリケーション内の秘密鍵を見つかりにくくするツールを提供します。これにより鍵をわかりにくくするため、攻撃者のアクセスをより難しくします。Unity のメニューで Window > Unity IAP > IAP Receipt Validation Obfuscator を選んでアクセスできます。
このウィンドウでは、Unity IAP に束ねられた Apple の ルート証明書と、アプリケーションのGoogle Play Developer Console の Services & APIs ページから取得する Google Play 公開キーを両方とも、2つの異なる C# ファイル、 AppleTangle と GooglePlayTangle にエンコードします。それらのC# ファイルは、プロジェクトに加えられ、次のセクションで使用されます。
注意: Apple ストアだけをターゲットにする場合は、Google Play 公開キーは必要ではありません。同様にGoogle Play だけをターゲットにする場合は、Apple のルート証明書は必要ではありません。
CrossPlatformValidator
クラスは、Google Play と Apple ストア両方の検証に使用することができます。
このクラスを使用するには、Google Play 公開キーか Apple の root 証明書が必要です。また、両方のプラットフォームを検証するなら両方が必要です。
CrossPlatformValidator
は 2つの検証を行います。
バリデーターは Google Play と Apple プラットフォームで作成されたレシートのみを検証することに注意してください。エディターで作成された偽造を含め、その他のプラットフォームで作成されたものには、IAPSecurityException 例外が発生します。
必要な機密を提供していないプラットフォームのレシートを検証しようとすると、MissingStoreSecretException 例外が発生します。
public PurchaseProcessingResult ProcessPurchase (PurchaseEventArgs e)
{
bool validPurchase = true; // R.V. のないプラットフォームに有効です
// Unity IAP の検証ロジックはこれらのプラットフォームにのみ含まれます。
# if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
// エディターの難読化ウィンドウで準備した機密を持つ
// バリデーターを準備します。
var validator = new CrossPlatformValidator(GooglePlayTangle.Data(),
AppleTangle.Data(), Application.bundleIdentifier);
try {
// Google Play で、result は 1 つの product ID を取得します
// Apple stores で、receipts には複数のプロダクトが含まれます
var result = validator.Validate(e.purchasedProduct.receipt);
// 情報提供の目的で、ここにレシートをリストします
Debug.Log("Receipt is valid. Contents:");
foreach (IPurchaseReceipt productReceipt in result) {
Debug.Log(productReceipt.productID);
Debug.Log(productReceipt.purchaseDate);
Debug.Log(productReceipt.transactionID);
}
} catch (IAPSecurityException) {
Debug.Log("Invalid receipt, not unlocking content");
validPurchase = false;
}
# endif
if (validPurchase) {
// 適当なコンテンツをここにアンロックします
}
return PurchaseProcessingResult.Complete;
}
レシートの有効性だけをチェックするのではなく、それに含まれる情報をチェックすることも大切です。ハッカーが実際に購入せずにコンテンツにアクセスする一般的な攻撃方法は、他のプロダクトやアプリケーションのレシートを提供することです。それらのレシートは純正なので、検証に引っかかりません。そのため、CrossPlatformValidator で分析したプロダクト ID に基づいて判断する必要があります。
それぞれのストアの購入レシートには、異なる欄があります。そのストア特有の欄にアクセスするには、 IPurchaseReceipt
を 2つの異なるサブタイプ GooglePlayReceipt
と AppleInAppPurchaseReceipt
にダウンキャストすることができます。
var result = validator.Validate(e.purchasedProduct.receipt);
Debug.Log("Receipt is valid. Contents:");
foreach (IPurchaseReceipt productReceipt in result) {
Debug.Log(productReceipt.productID);
Debug.Log(productReceipt.purchaseDate);
Debug.Log(productReceipt.transactionID);
GooglePlayReceipt google = productReceipt as GooglePlayReceipt;
if (null != google) {
// ここに Google のオーダー ID
// sandbox でテストする場合は null にするように注意
// なぜなら、Google の sandbox はオーダー IDを発行しないため
Debug.Log(google.transactionID);
Debug.Log(google.purchaseState);
Debug.Log(google.purchaseToken);
}
AppleInAppPurchaseReceipt apple = productReceipt as AppleInAppPurchaseReceipt;
if (null != apple) {
Debug.Log(apple.originalTransactionIdentifier);
Debug.Log(apple.subscriptionExpirationDate);
Debug.Log(apple.cancellationDate);
Debug.Log(apple.quantity);
}
}
AppleValidator
クラスは、Apple レシートの詳細な情報を取り出すのに使用されます。このクラスは、Apple の Deprecated トランザクション レシートではなく、iOS 7 以降のバージョンの App Store レシートにのみ正しく機能することに気を付けてください。
# if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
// IAP 初期化の間に、IAppleConfiguration への参照を取得
var appleConfig = builder.Configure<IAppleConfiguration>();
var receiptData = System.Convert.FromBase64String(appleConfig.appReceipt);
AppleReceipt receipt = new AppleValidator(AppleTangle.Data()).Validate(receiptData);
Debug.Log(receipt.bundleID);
Debug.Log(receipt.receiptCreationDate);
foreach (AppleInAppPurchaseReceipt productReceipt in receipt.inAppPurchaseReceipts) {
Debug.Log(productReceipt.transactionIdentifier);
Debug.Log(productReceipt.productIdentifier);
}
# endif
AppleReceipt
タイプは Apple の ASN1 レシート形式をモデルにしています。詳細は Apple のドキュメンテーション を参照してください。
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.