ti-enxame.com

Como verifico Android transações de cobrança no aplicativo em MEU servidor?

Eu criei um aplicativo Android onde itens podem ser comprados usando in-app-billing . Quando um item é comprado, a transação pode ser facilmente sincronizada entre o Android Market e o telefone - para ser usado no aplicativo. Mas, preciso que o meu servidor esteja ciente da compra. A decisão de fornecer dados específicos do aplicativo deve ser tomada no meu servidor, não no aplicativo cliente.

Por exemplo.

  1. O usuário compra o item X do mercado Android.
  2. Os dados da transação Y são enviados ao cliente.
  3. O cliente envia Y para o meu servidor.
  4. O cliente solicita ao servidor que entregue conteúdo para o X.
  5. O servidor entrega conteúdo se Y for válido . Como pode ser isto alcançado?

P: Como verifico se os dados de transação provenientes do cliente Android (provavelmente originários dos servidores do Google) não são falsos? I.e. um hacker não gerou os dados.

Servidor Google -> cliente Android -> Meu servidor -> cliente Android

Talvez isso seja mais uma questão PHP do que qualquer outra coisa. Exatamente o que meu script de servidor (PHP) deve fazer para verificar se os dados recuperados são reais?

34
l33t

Use openssl_verify ($ data, $ assinatura, $ chave)

As variáveis ​​$ data e $ signature devem ser enviadas do cliente Android para o servidor php usando https. A transação contém esses dois itens. Envie-os aos seus servidores antes de confirmar a transação no cliente. (consulte a documentação aqui - http://developer.Android.com/guide/market/billing/billing_integrate.html )

A variável $ key é a sua chave pública do Google, disponível na sua conta de editor no painel Licenciamento e cobrança no aplicativo. Copie a chave pública e use-a no seu código php, de preferência usando um arquivo de configuração que você instala em seus servidores, e não no seu código php real.

Se a chamada openssl_verify for bem-sucedida, você deve armazenar os números dos pedidos em seus servidores e garantir que eles sejam exclusivos para que não possam ser reproduzidos novamente. Esteja ciente de que um único par de recebimento e assinatura de dados pode conter muitos números de pedidos, embora seja geralmente um pedido.

20
abdollar

Usamos AndroidBillingLibrary .

Instale isso como um projeto no Eclipse e deixe seu projeto importá-lo como uma biblioteca.

Implementamos o BillingController.IConfiguration, algo como

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";
    }
}

Em seguida, para nosso aplicativo, estendemos Application:

public class LocalizedApplication extends Application {

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

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

AndroidManifest inclui isso (e todas as outras coisas)

<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>

Implementamos 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;
    }

}

São as últimas linhas acima que chamam sua classe que realmente conversam com seu servidor.

Nosso PhoneServerLink inicia algo como isto:

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

Os dados da transação são assinados com uma chave privada específica do seu aplicativo. Também existe um impedimento para impedir replays (ou seja, enviar os mesmos dados válidos várias vezes). Se você verificar que o nonce é exclusivo e a assinatura é válida no seu servidor, pode ter certeza razoável de que não é falso. Verifique a parte sobre o IAB de este Google IO apresentação para uma discussão.

4
Nikolay Elenkov