レシート検証によって、ユーザーが購入していないコンテンツにアクセスすることを防ぎます。
重要: Unity IAP はローカルな検証方法を提供していますが、ローカルな検証は不正に対してより脆弱です。可能であれば、機密性の高いトランザクションをサーバーサイドで検証することがベストプラクティスと考えられます。詳細については、不正防止に関する Apple および Android のドキュメントを参照してください。
ユーザーが購入するコンテンツがすでにデバイスに存在する場合は、アプリケーションはただ、それをアンロックするかどうかを決定するだけです。
Unity IAP はコンテンツを隠し、Google Play と App Store をとおしてレシートを検証し分析するツールを提供します。
レシート検証は既知の暗号化キーを使用して実行されます。Unity ユーザーのアプリケーションの場合は、暗号化された Google Play 公開鍵や Apple のルート証明書などです。
攻撃者がこれらの機密情報を置き換えることができると、レシート検証は失敗してしまいます。そのため、攻撃者が簡単にこれらのキーを見つけ、改変できないようにすることが大切です。
Unity IAP はアプリケーション内の秘密鍵を見つかりにくくするツールを提供します。このツールが鍵をわかりにくくするため、攻撃者によるアクセスはより難しくなります。Unity のメニューで Window > Unity IAP > IAP Receipt Validation Obfuscator に移動してください。
このウィンドウで、Apple のルート証明書 (Unity IAP にバンドル) と Google Play 公開鍵 (アプリケーションの Google Play 開発者コンソールの Services & APIs ページから) の両方を、2 つの異なる C# ファイル (AppleTangle と GooglePlayTangle) にエンコードできます。これらは、次のセクションで使用するためにプロジェクトに追加されます。
注意: 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; // Presume valid for platforms with no R.V.
// Unity IAP's validation logic is only included on these platforms.
#if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
// Prepare the validator with the secrets we prepared in the Editor
// obfuscation window.
var validator = new CrossPlatformValidator(GooglePlayTangle.Data(),
AppleTangle.Data(), Application.bundleIdentifier);
try {
// On Google Play, result has a single product ID.
// On Apple stores, receipts contain multiple products.
var result = validator.Validate(e.purchasedProduct.receipt);
// For informational purposes, we list the receipt(s)
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) {
// Unlock the appropriate content here.
}
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) {
// This is Google's Order ID.
// Note that it is null when testing in the sandbox
// because Google's sandbox does not provide Order IDs.
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 の廃止予定のトランザクションレシートではなく、iOS 7.0 以降のバージョンの App Store レシートにのみ正しく機能するため、注意してください。
#if UNITY_ANDROID || UNITY_IOS || UNITY_STANDALONE_OSX
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
// Get a reference to IAppleConfiguration during IAP initialization.
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 のドキュメントを参照してください。