テーマ、知りたいこと
iOSのサブスクのアプリ課金を実装しています。
アプリで課金操作を行った後にアプリサーバーにその課金情報を反映させます。
verifyReceipt APIが非推奨になっているので、代替の手段を知りたいです。言語はnodejs
この質問での「課金のレシート」はMII~ から始まるASN.1のbase64です。jwt ではありません。
今まではアプリで課金操作をした後にStoreKitから受け取ったレシートをそのままアプリサーバーに投げて、そのアプリサーバーからverifyReceipt APIにそのまま投げてレシートのjsonを取得していました。
悪意あるユーザーがデタラメなレシートを送ったとしても、そのレシートはAppleの署名がされていないので verifyreceipt APIでエラーになって気づく事が出来ました。
しかしverifyreceipt APIは非推奨になり、いつ消えるか分からない状態です。
https://developer.apple.com/documentation/appstorereceipts/verifyreceipt
色々な記事を見ると「サーバーにトランザクションIDを送り、サーバー側ではAppStoreServerAPIを使ってトランザクションの詳細情報を取得する」という方法が代替案として提示されていて
https://speakerdeck.com/yuheiito/storekit2woshi-tutake-jin-sisutemunohururiniyuaru?slide=29
Apple公式の Apple App Store Server Node.js Library でも
https://github.com/apple/app-store-server-library-node
レシート検証の処理は以下の用に記述されています。
const appReceipt = "MI..." const receiptUtil = new ReceiptUtility() const transactionId = receiptUtil.extractTransactionIdFromAppReceipt(appReceipt)
このどちらの方法も「デタラメのトランザクションIDをアプリサーバーにPOSTされたら無課金でサブスクに加入されてしまうのでは?」という不安があります。
MII~ から始まる文字列のレシートはASN.1という形式で、特定のプロパティのみデタラメな値に差し替える事は可能なはずです。
Apple公式のnodejsのライブラリの該当処理のロジックを追いかけたのですが、レシートのbase64からトランザクションIDのプロパティを読み込んでいるだけでAppleの証明書の検証はしていません。
また、前者のspeakerdeckの例においては「サーバーにトランザクションIDを送る」と書いているのでトランザクションIDの数字を信じるしかない状態だと思います。
これ、アプリから渡されたトランザクションIDの数字をそのまま信用してよいのでしょうか?
アプリを解析とかiOSに中間者攻撃を仕掛ければアプリサーバーへの通信内容は丸裸ですし、
そこで不正に入手されたトランザクションIDを投げ込まれたらアプリサーバーはそれを受け入れてしまうはずです。
※
StoreKit2の jwsRepresentation というプロパティを使えばjwsが取れて、
jwsは一般的な方法で証明書の検証が出来ると思いますが、flutterを使っているのでこの方法は現状使えません。
あくまでアプリから送られてくるのはMII~ から始まるレシートのbase64から変更出来ない想定です。
https://developer.apple.com/documentation/storekit/verificationresult/jwsrepresentation-21vgo
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。