web-dev-qa-db-ja.com

MYサーバーでAndroidアプリ内課金トランザクションを確認するにはどうすればよいですか?

in-app-billing を使用してアイテムを購入できるAndroidアプリを作成しました。アイテムを購入すると、Android Marketと電話の間でトランザクションを簡単に同期でき、アプリで使用できます。しかし、購入を認識できるようにMYサーバーが必要です。アプリ固有のデータを配信するかどうかの決定は、クライアントアプリではなくサーバーで行う必要があります。

例えば。

  1. ユーザーはAndroidマーケットからアイテムXを購入します。
  2. トランザクションデータYがクライアントに送信されます。
  3. クライアントがYをサーバーに送信します。
  4. クライアントはサーバーにXのコンテンツを配信するように要求します。
  5. Yが有効な場合、サーバーはコンテンツを配信します。どうすればこれを達成できますか?

Q:Androidクライアント(おそらくGoogleサーバーから送信されたもの)からのトランザクションデータが偽物ではないことを確認するにはどうすればよいですか?つまりハッカーはデータを生成しませんでした。

Googleサーバー-> Androidクライアント->マイサーバー-> Androidクライアント

おそらく、これは他の何よりもPHPの質問のほうが多いでしょう。取得したデータが本物であることを確認するために、サーバースクリプト(PHP)は何をすべきですか?

34
l33t

Openssl_verify($ data、$ signature、$ key)を使用します

変数$ dataと$ signatureは、Androidクライアントからhttpsを使用してphpサーバーに送信する必要があります。トランザクションには、これらの両方のアイテムが含まれています。クライアント(ここにドキュメントを参照してください- http://developer.Android.com/guide/market/billing/billing_integrate.html

変数$ keyは、[ライセンスとアプリ内課金]パネルのパブリッシャーアカウントから入手できるGoogleの公開鍵です。公開鍵をコピーして、phpコードで使用します。できれば、実際のphpコードではなく、サーバーにインストールした設定ファイルを使用してください。

Openssl_verifyの呼び出しが成功した場合は、注文番号をサーバーに保存し、注文番号が一意であることを確認して、再生できないようにする必要があります。 1つのデータ受信と署名のペアには、通常は1つの注文であるが、多くの注文番号が含まれる場合があることに注意してください。

20
abdollar

AndroidBillingLibrary を使用しました。

それをEclipseのプロジェクトとしてインストールし、プロジェクトにライブラリとしてインポートさせます。

次のようなBillingController.IConfigurationを実装しました

import net.robotmedia.billing.BillingController;

public class PhoneBillingConfiguration implements BillingController.IConfiguration{
    @Override
    public byte[] getObfuscationSalt() {
        return new byte[] {1,-2,3,4,-5,6,-7,theseshouldallberandombyteshere,8,-9,0};
    }

    @Override
    public String getPublicKey() {
        return "superlongstringhereIforgothowwemadethis";
    }
}

次に、アプリケーションでApplicationを拡張しました。

public class LocalizedApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

//      BillingController.setDebug(true);
        BillingController.setConfiguration(new PhoneBillingConfiguration());
    }
}

AndroidManifestにはこれ(およびその他すべてのもの)が含まれています

<application
    Android:icon="@drawable/icon"
    Android:label="@string/app_name"
    Android:name=".LocalizedApplication"   <!-- use your specific Application  -->
    Android:largeHeap="true"
    Android:hardwareAccelerated="true"
    >

    <!-- For billing -->
    <service Android:name="net.robotmedia.billing.BillingService" />
        <receiver Android:name="net.robotmedia.billing.BillingReceiver">
        <intent-filter>
            <action Android:name="com.Android.vending.billing.IN_APP_NOTIFY" />
            <action Android:name="com.Android.vending.billing.RESPONSE_CODE" />
            <action Android:name="com.Android.vending.billing.PURCHASE_STATE_CHANGED" />
        </intent-filter>
    </receiver>

ISignatureValidatorを実装しました

public class PhoneSignatureValidator implements ISignatureValidator {
    private final String TAG = this.getClass().getSimpleName();
    private PhoneServerLink mServerLink;


    private BillingController.IConfiguration configuration;

    public PhoneSignatureValidator(Context context, BillingController.IConfiguration configuration, String our_product_sku) {
        this.configuration = configuration;
        mServerLink = new PhoneServerLink(context);
        mServerLink.setSku(our_product_sku);
    }


    @Override
    public boolean validate(String signedData, String signature) {
        final String publicKey;
        if (configuration == null || TextUtils.isEmpty(publicKey = configuration.getPublicKey())) {
            Log.w(BillingController.LOG_TAG, "Please set the public key or turn on debug mode");
            return false;
        }
        if (signedData == null) {
            Log.e(BillingController.LOG_TAG, "Data is null");
            return false;
        }
        // mServerLink will talk to your server
        boolean bool = mServerLink.validateSignature(signedData, signature);
        return bool;
    }

}

実際にサーバーと通信するのは、クラスを呼び出す上記の最後の数行です。

PhoneServerLinkは次のようなものから始まります。

public class PhoneServerLink implements GetJSONListener {

    public PhoneServerLink(Context context) {
        mContext = context;
    }

    public boolean validateSignature(String signedData, String signature) {
        return getPurchaseResultFromServer(signedData, signature, false);
    }

    private boolean getPurchaseResultFromServer(String signedData, String signature,  boolean async) {  
            // send request to server using whatever protocols you like 
    }

}
11
Thunder Rabbit

トランザクションデータは、アプリ固有の秘密鍵で署名されています。また、再生を防止するナンスもあります(つまり、同じ有効なデータを複数回送信する)。 nonceが一意であり、サーバーで署名が有効であることを確認すると、偽物ではないことを合理的に確信できます。ディスカッションについては、 this Google IO presentation のIABに関する部分を確認してください。

4
Nikolay Elenkov