Как проверить транзакции Android-навязывания на моем сервере?
-
28-10-2019 - |
Вопрос
Я сделал приложение для Android, где предметы можно приобрести с помощью навязывание приложений. Анкет Когда предмет приобретен, транзакция может быть легко синхронизирована между рынком Android и телефона - для использования в приложении. Но мне нужен мой сервер, чтобы знать о покупке. Решение о доставке данных, специфичных для приложений, должно быть принято на моем сервере, а не в клиентском приложении.
Например
- Пользователь покупает Item X от Android Market.
- Данные транзакции Y отправляется клиенту.
- Клиент отправляет Y на мой сервер.
- Клиент просит сервер доставить контент для X.
- Сервер обеспечивает контент Если y действителен. Анкет Как это можно сделать?
Q: Как я могу проверить, что данные о транзакциях, поступающие от клиента Android (предположительно, происходящее с серверов Google), не являются фальшивыми? Т.е. хакер не генерировал данные.
Google Server -> Android Client -> My Server -> Android Client
Возможно, это скорее вопрос PHP, чем что -либо еще. Что именно должен делать мой скрипт сервера (PHP), чтобы убедиться, что полученные данные реальны?
Решение
Используйте openssl_verify ($ data, $ signature, $ key)
Переменные данные $ и подпись $ должны быть отправлены с клиента Android на ваш PHP -сервер с помощью HTTPS. Транзакция содержит оба этих элемента. Отправьте это своим серверам, прежде чем вы подтвердите транзакцию на клиенте. (См. Документация здесь - http://developer.android.com/guide/market/billing/billing_integrate.html)
Ключ переменной $-это ваш общедоступный ключ Google, доступный из вашей учетной записи издателя из лицензионной и вкладной платежной панели. Скопируйте открытый ключ и используйте его в своем коде PHP, предпочтительно, используя файл конфигурации, который вы устанавливаете на своих серверах, а не в своем фактическом коде PHP.
Если вызов openssl_verify добивается успеха, вы должны сохранить номера заказа на своих серверах и убедиться, что они уникальны, поэтому их нельзя воспроизвести. Имейте в виду, что единая квитанция и подпись может содержать много чисел заказа, хотя обычно его заказ.
Другие советы
Мы использовали 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;
}
}
Это последние несколько строк выше, которые называют ваш класс, которые на самом деле будут разговаривать с вашим сервером.
Наш телефонный директор начинает что -то вроде этого:
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
}
}
Данные о транзакциях подписаны с закрытым ключом, специфичным для вашего приложения. Существует также nonce, чтобы предотвратить повтор (т.е. отправка одинаковых, допустимых данных несколько раз). Если вы убедитесь, что Nonce уникален, а подпись действительна на вашем сервере, вы можете быть достаточно уверены, что это не подделка. Проверьте часть о IAB это презентация Google IO для обсуждения.