Weryfikowanie wywołań zwrotnych po stronie serwera (SSV)

Wywołania zwrotne weryfikacji po stronie serwera to żądania adresów URL z parametrami zapytania rozszerzone przez Google, które są wysyłane przez Google do systemu zewnętrznego w celu powiadomić go, że użytkownik powinien być nagrodzony za interakcję z reklama pełnoekranowa z nagrodą. Wywołania zwrotne SSV (weryfikacja po stronie serwera) zapewniają dodatkową warstwę ochrony przed podszywaniem się w wywołaniach zwrotnych po stronie klienta; aby nagradzać użytkowników.

Z tego przewodnika dowiesz się, jak zweryfikować wywołania zwrotne SSV z nagrodą za pomocą Aplikacje w Javie Tink innych firm biblioteki kryptograficznej, by zapewnić, że parametry zapytania w wywołaniu zwrotnym będą prawidłowe wartości. Chociaż w tym przewodniku Tink jest używany, możesz korzystać z biblioteki innej firmy, która obsługuje ECDSA Serwer możesz też przetestować za pomocą testowania w interfejsie AdMob.

Zobacz w pełni działającą przykład za pomocą Sprężynowego rozruchu Java.

Wymagania wstępne

Korzystanie z narzędzia NagrodyAdsVerifier z biblioteki aplikacji Tink w języku Java

repozytorium Tink Java Apps na GitHubie. zawiera RewardedAdsVerifier. klasy pomocniczej, aby zmniejszyć kod wymagany do weryfikacji wywołania zwrotnego SSV z nagrodą. Użycie tej klasy umożliwia zweryfikowanie adresu URL wywołania zwrotnego za pomocą poniższego kodu.

RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
    .fetchVerifyingPublicKeysWith(
        RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
    .build();
String rewardUrl = ...;
verifier.verify(rewardUrl);

Jeśli metoda verify() zostanie wykonana bez zgłaszania wyjątku, wywołanie zwrotne Adres URL został zweryfikowany. Pole Nagradzanie użytkowników zawiera szczegółowe informacje o sprawdzonych metodach dotyczących tego, kiedy użytkownicy powinni otrzymywać nagrody. Dla zestawienie czynności wykonywanych przez tę klasę w celu weryfikacji wywołań zwrotnych SSV z nagrodą przeczytaj artykuł Ręczna weryfikacja reklam z nagrodą SSV.

Parametry wywołania zwrotnego SSV

Wywołania zwrotne weryfikacji po stronie serwera zawierają parametry zapytania opisujące interakcji z reklamą z nagrodą. Nazwy parametrów, opisy i przykładowe wartości to wymienionych poniżej. Parametry są wysyłane w kolejności alfabetycznej.

Nazwa parametru Opis Przykładowa wartość
ad_network Identyfikator źródła reklam, które wyświetliło tę reklamę. Źródło reklam nazwy odpowiadające wartościom identyfikatora są wymienione na liście identyfikatory źródeł. 1953547073528090325
ad_unit Identyfikator jednostki reklamowej AdMob użytej do wysłania żądania reklamy z nagrodą. 2747237135
custom_data Niestandardowy ciąg danych dostarczony przez setCustomData .

Jeśli aplikacja nie podaje niestandardowego ciągu danych, ten parametr zapytania nie zostanie podana w wywołaniu zwrotnym SSV.

SAMPLE_CUSTOM_DATA_STRING
key_id Klucz używany do weryfikacji wywołania zwrotnego SSV. Ta wartość jest mapowana na klucz publiczny dostarcza serwer kluczy AdMob. 1234567890
reward_amount Kwota nagrody określona w ustawieniach jednostki reklamowej. 5
reward_item Przedmiot nagrody zgodnie z ustawieniami jednostki reklamowej. monety
podpis Podpis wywołania zwrotnego SSV wygenerowany przez AdMob. MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY
sygnatura czasowa Sygnatura czasowa momentu (w milisekundach) przyznania użytkownikowi nagrody w postaci czasu epoki. 1507770365237823
transaction_id Unikalny, zakodowany szesnastkowo identyfikator każdego zdarzenia przyznania nagrody wygenerowanego przez AdMob. 18fa792de1bca816048293fc71035638
user_id Identyfikator użytkownika podany przez setUserId

Jeśli aplikacja nie podaje identyfikatora użytkownika, ten parametr zapytania nie będzie w wywołaniu zwrotnym SSV.

1234567

Identyfikatory źródeł reklam

Nazwy i identyfikatory źródeł reklam

Nazwa źródła reklamy Identyfikator źródła reklam
Aarki (określanie stawek)5240798063227064260
Generowanie reklam (ustalanie stawek)1477265452970951479
AdColony15586990674969969776
AdColony (poza pakietem SDK) (określanie stawek)4600416542059544716
AdColony (określanie stawek)6895345910719072481
AdFalcon3528208921554210682
Sieć AdMob5450213213286189855
Kaskada sieci AdMob1215381445328257950
ADResult10593873382626181482
AMoAd17253994435944008978
Applovin,1063618907739174004
Applovin (określanie stawek)1328079684332308356
Chartboost2873236629771172317
Platforma czekolady (określanie stawek)6432849193975106527
Wiele kanałów (MdotM)9372067028804390441
Zdarzenie niestandardowe18351550913290782395
DT Exchange*
* Przed 21 września 2022 r. sieć nosiła nazwę „Fyber Marketplace”.
2179455223494392917
EMX (określanie stawek)8497809869790333482
Zmienność (ustalanie stawek)8419777862490735710
Lekkie3376427960656545613
Fyber*
* To źródło reklam służy do raportowania historycznego.
4839637394546996422
i-mobile5208827440166355534
Ulepszaj reklamy cyfrowe (ustalanie stawek)159382223051638006
Index Exchange (ustalanie stawek)4100650709078789802
InMobi7681903010231960328
InMobi (określanie stawek)6325663098072678541
Giełda InMobi (określanie stawek)5264320421916134407
IronSource6925240245545091930
Reklamy ironSource (ustalanie stawek)1643326773739866623
Leadbolt2899150749497968595
LG U+AD18298738678491729107
Sieć reklamowa LINE3025503711505004547
Maio7505118203095108657
maio (określanie stawek)1343336733822567166
Media.net (określanie stawek)2127936450554446159
Zapośredniczone autoreklamy6060308706800320801
Meta Audience Network*
* Przed 6 czerwca 2022 r. sieć nosiła nazwę „Facebook Audience Network”.
10568273599589928883
Meta Audience Network (określanie stawek)*
* Przed 6 czerwca 2022 r. sieć nosiła nazwę „Facebook Audience Network (określanie stawek)”.
11198165126854996598
Mintegral1357746574408896200
Mintegral (określanie stawek)6250601289653372374
MobFox8079529624516381459
MobFox (określanie stawek)3086513548163922365
MoPub (wycofane)10872986198578383917
myTarget8450873672465271579
Nend9383070032774777750
Nexxen (określanie stawek)*

* Przed 1 maja 2024 r. sieć ta nazywała się „UnrulyX”.

2831998725945605450
ONE by AOL (Millennial Media)6101072188699264581
ONE by AOL (Nexage)3224789793037044399
OneTag Exchange (ustalanie stawek)4873891452523427499
OpenX (określanie stawek)4918705482605678398
Pangle4069896914521993236
Pangle (określanie stawek)3525379893916449117
PubMatic (określanie stawek)3841544486172445473
Kampania z rezerwacją7068401028668408324
RhythmOne (określanie stawek)2831998725945605450
Rubicon (określanie stawek)3993193775968767067
Planeta SK734341340207269415
Współczynnik udziału (określanie stawek)5247944089976324188
Smaato (określanie stawek)3362360112145450544
Równy (określanie stawek)*

* Do 12 stycznia 2023 r. sieć ta nazywała się „Smart Adserver”.

5970199210771591442
Sonobi (określanie stawek)3270984106996027150
Tapjoy7295217276740746030
Tapjoy (określanie stawek)4692500501762622178
Tencent (GDT)7007906637038700218
TripleLift (określanie stawek)8332676245392738510
Reklamy Unity4970775877303683148
Reklamy Unity (określanie stawek)7069338991535737586
Verizon Media,7360851262951344112
Grupa Verve (określanie stawek)5013176581647059185
Vpon1940957084538325905
Liftoff – zarabianie*

* Przed 30 stycznia 2023 r. sieć ta nazywała się „Vungle”.

1953547073528090325
Liftoff Monetize (określanie stawek)*

* Przed 30 stycznia 2023 r. sieć ta nosiła nazwę „Vungle (określanie stawek)”.

4692500501762622185
Yieldmo (określanie stawek)4193081836471107579
YieldOne (określanie stawek)3154533971590234104
Kaczki5506531810221735863

Nagradzanie użytkownika

Ważne jest zachowanie równowagi między wygodą użytkowników a weryfikacją nagród i określić, kiedy należy nagradzać użytkownika. W przypadku wywołań zwrotnych po stronie serwera mogą wystąpić opóźnienia przed które docierają do systemów zewnętrznych. Dlatego zalecamy stosowanie wywołanie zwrotne po stronie klienta, by natychmiast nagrodzić użytkownika, weryfikacji wszystkich nagród po otrzymaniu wywołań zwrotnych po stronie serwera. Ten zapewnia wygodę użytkownikom, a jednocześnie zapewnienie prawidłowości nagrody.

Jednak w aplikacjach, w których ważność nagrody jest kluczowa (na przykład wpływa na ekonomię w grze), a opóźnienia w ich przyznawaniu są akceptowalne, najlepszym rozwiązaniem jest oczekiwanie na zweryfikowane wywołanie zwrotne po stronie serwera. jak ważna jest pokora.

Dane niestandardowe

W przypadku aplikacji, które wymagają dodatkowych danych w wywołaniach zwrotnych weryfikacji po stronie serwera, należy użyć parametru niestandardowe dane reklam z nagrodą. Dowolny ciąg znaków ustawiony w reklamie z nagrodą jest przekazywany do parametru zapytania custom_data w wywołaniu zwrotnym SSV. Jeśli nie niestandardowych wartości danych, wartość parametru zapytania custom_data nie będzie w wywołaniu zwrotnym SSV.

Poniższy przykładowy kod pokazuje, jak ustawić opcje SSV po tagu reklama z nagrodą została wczytana.

Java

RewardedAd.load(MainActivity.this, "ca-app-pub-3940256099942544/5354046379",
    new AdRequest.Builder().build(),  new RewardedAdLoadCallback() {
  @Override
  public void onAdLoaded(RewardedAd ad) {
    Log.d(TAG, "Ad was loaded.");
    rewardedAd = ad;
    ServerSideVerificationOptions options = new ServerSideVerificationOptions
        .Builder()
        .setCustomData("SAMPLE_CUSTOM_DATA_STRING")
        .build();
    rewardedAd.setServerSideVerificationOptions(options);
  }
  @Override
  public void onAdFailedToLoad(LoadAdError loadAdError) {
    Log.d(TAG, loadAdError.toString());
    rewardedAd = null;
  }
});

Kotlin

RewardedAd.load(this, "ca-app-pub-3940256099942544/5354046379",
    AdRequest.Builder().build(), object : RewardedAdLoadCallback() {
  override fun onAdLoaded(ad: RewardedAd) {
    Log.d(TAG, "Ad was loaded.")
    rewardedInterstitialAd = ad
    val options = ServerSideVerificationOptions.Builder()
        .setCustomData("SAMPLE_CUSTOM_DATA_STRING")
        .build()
    rewardedAd.setServerSideVerificationOptions(options)
  }

  override fun onAdFailedToLoad(adError: LoadAdError) {
    Log.d(TAG, adError?.toString())
    rewardedAd = null
  }
})

Jeśli chcesz ustawić niestandardowy ciąg nagrody, musisz to zrobić przed wyświetleniem reklamę.

Ręczna weryfikacja reklamy SSV z nagrodą

Czynności wykonywane przez klasę RewardedAdsVerifier w celu zweryfikowania reklamy z nagrodą Poniżej znajdziesz opis usługi SSV. Mimo że dołączone fragmenty kodu są w języku Java jeśli korzystasz z biblioteki zewnętrznej Tink, możesz wykonać te czynności w wybranym języku, używając do tego dowolnej biblioteki zewnętrznej, która obsługuje ECDSA

Pobierz klucze publiczne

Aby zweryfikować wywołanie zwrotne SSV z nagrodą, potrzebujesz klucza publicznego dostarczonego przez AdMob.

Lista kluczy publicznych używanych do weryfikacji wywołań zwrotnych SSV z nagrodą może być pobrane z klucza AdMob Lista kluczy publicznych jest podana w postaci reprezentacji JSON w formacie podobnym do tego:

{
 "keys": [
    {
      keyId: 1916455855,
      pem: "-----BEGIN PUBLIC KEY-----\nMF...YTPcw==\n-----END PUBLIC KEY-----"
      base64: "MFkwEwYHKoZIzj0CAQYI...ltS4nzc9yjmhgVQOlmSS6unqvN9t8sqajRTPcw=="
    },
    {
      keyId: 3901585526,
      pem: "-----BEGIN PUBLIC KEY-----\nMF...aDUsw==\n-----END PUBLIC KEY-----"
      base64: "MFYwEAYHKoZIzj0CAQYF...4akdWbWDCUrMMGIV27/3/e7UuKSEonjGvaDUsw=="
    },
  ],
}

Aby pobrać klucze publiczne, połącz się z serwerem kluczy AdMob i pobierz plik klawiszy. Następujący kod wykonuje to zadanie i zapisuje JSON reprezentacja kluczy do zmiennej data.

String url = ...;
NetHttpTransport httpTransport = new NetHttpTransport.Builder().build();
HttpRequest httpRequest =
    httpTransport.createRequestFactory().buildGetRequest(new GenericUrl(url));
HttpResponse httpResponse = httpRequest.execute();
if (httpResponse.getStatusCode() != HttpStatusCodes.STATUS_CODE_OK) {
  throw new IOException("Unexpected status code = " + httpResponse.getStatusCode());
}
String data;
InputStream contentStream = httpResponse.getContent();
try {
  InputStreamReader reader = new InputStreamReader(contentStream, UTF_8);
  data = readerToString(reader);
} finally {
  contentStream.close();
}

Pamiętaj, że klucze publiczne są regularnie poddawane rotacji. Otrzymasz e-maila z informacjami o nadchodzącej rotacji. Jeśli buforujesz klucze publiczne, musisz zaktualizować klucze.

Po pobraniu kluczy publicznych należy je przeanalizować. Poniższa metoda parsePublicKeysJson pobiera ciąg znaków JSON, jak w przykładzie. powyżej jako danych wejściowych i tworzy mapowanie z wartości key_id na klucze publiczne, zapakowane jako obiekty ECPublicKey z biblioteki Tink.

private static Map<Integer, ECPublicKey> parsePublicKeysJson(String publicKeysJson)
    throws GeneralSecurityException {
  Map<Integer, ECPublicKey> publicKeys = new HashMap<>();
  try {
    JSONArray keys = new JSONObject(publicKeysJson).getJSONArray("keys");
    for (int i = 0; i < keys.length(); i++) {
      JSONObject key = keys.getJSONObject(i);
      publicKeys.put(
          key.getInt("keyId"),
          EllipticCurves.getEcPublicKey(Base64.decode(key.getString("base64"))));
    }
  } catch (JSONException e) {
    throw new GeneralSecurityException("failed to extract trusted signing public keys", e);
  }
  if (publicKeys.isEmpty()) {
    throw new GeneralSecurityException("No trusted keys are available.");
  }
  return publicKeys;
}

Pobieranie treści do zweryfikowania

Ostatnie 2 parametry zapytania wywołań zwrotnych SSV z nagrodą mają zawsze wartość signature i key_id, w tej kolejności. Pozostałe parametry zapytania określają treść do weryfikacji. Załóżmy, że skonfigurujesz w AdMob wysyłanie wywołań zwrotnych do nagrody https://www.myserver.com/mypath Fragment kodu poniżej zawiera przykład reklamy z nagrodą Wywołanie zwrotne SSV z wyróżnioną treścią do zweryfikowania.

https://www.myserver.com/path?ad_network=54...55&ad_unit=12345678&reward_amount=10&reward_item=coins
&timestamp=150777823&transaction_id=12...DEF&user_id=1234567&signature=ME...Z1c&key_id=1268887

Poniższy kod pokazuje, jak przeanalizować treść, która ma zostać zweryfikowana adresu URL wywołania zwrotnego jako tablicy UTF-8.

public static final String SIGNATURE_PARAM_NAME = "signature=";
...
URI uri;
try {
  uri = new URI(rewardUrl);
} catch (URISyntaxException ex) {
  throw new GeneralSecurityException(ex);
}
String queryString = uri.getQuery();
int i = queryString.indexOf(SIGNATURE_PARAM_NAME);
if (i == -1) {
  throw new GeneralSecurityException("needs a signature query parameter");
}
byte[] queryParamContentData =
    queryString
        .substring(0, i - 1)
        // i - 1 instead of i because of & in the query string
        .getBytes(Charset.forName("UTF-8"));

Pobieranie podpisu i identyfikatora key_id z adresu URL wywołania zwrotnego

Korzystając z wartości queryString z poprzedniego kroku, przeanalizuj analizy signature i Parametry zapytania key_id z adresu URL wywołania zwrotnego, jak pokazano poniżej:

public static final String KEY_ID_PARAM_NAME = "key_id=";
...
String sigAndKeyId = queryString.substring(i);
i = sigAndKeyId.indexOf(KEY_ID_PARAM_NAME);
if (i == -1) {
  throw new GeneralSecurityException("needs a key_id query parameter");
}
String sig =
    sigAndKeyId.substring(
        SIGNATURE_PARAM_NAME.length(), i - 1 /* i - 1 instead of i because of & */);
int keyId = Integer.valueOf(sigAndKeyId.substring(i + KEY_ID_PARAM_NAME.length()));

Przeprowadź weryfikację

Ostatnim krokiem jest weryfikacja treści adresu URL wywołania zwrotnego za pomocą atrybutu odpowiedni klucz publiczny. Użyj mapowania zwróconego z metody parsePublicKeysJson i użyj parametru key_id z wywołania zwrotnego Adres URL do pobrania klucza publicznego z tego mapowania. Następnie zweryfikuj podpis, używając taki klucz publiczny. Kroki te zostały opisane poniżej w metodzie verify.

private void verify(final byte[] dataToVerify, int keyId, final byte[] signature)
    throws GeneralSecurityException {
  Map<Integer, ECPublicKey> publicKeys = parsePublicKeysJson();
  if (publicKeys.containsKey(keyId)) {
    foundKeyId = true;
    ECPublicKey publicKey = publicKeys.get(keyId);
    EcdsaVerifyJce verifier = new EcdsaVerifyJce(publicKey, HashType.SHA256, EcdsaEncoding.DER);
    verifier.verify(signature, dataToVerify);
  } else {
    throw new GeneralSecurityException("cannot find verifying key with key ID: " + keyId);
  }
}

Jeśli metoda jest wykonywana bez zgłaszania wyjątku, adres URL wywołania zwrotnego miał postać zweryfikowano.

Najczęstsze pytania

Czy mogę zapisać w pamięci podręcznej klucz publiczny udostępniony przez serwer kluczy AdMob?
Zalecamy zapisywanie w pamięci podręcznej klucza publicznego dostarczonego przez klucz AdMob serwera, aby zmniejszyć liczbę operacji wymaganych do weryfikacji SSV . Pamiętaj jednak, że klucze publiczne są regularnie poddawane rotacji i nie należy ich mogą być przechowywane w pamięci podręcznej dłużej niż 24 godziny.
Jak często poddawana jest rotacja kluczy publicznych dostarczanych przez serwer kluczy AdMob?
Klucze publiczne przekazane przez serwer kluczy AdMob są poddawane rotacji na zmiennej harmonogram. Aby weryfikacja wywołań zwrotnych SSV nadal działała kluczy publicznych nie należy przechowywać w pamięci podręcznej dłużej niż przez 24 godziny.
Co się stanie, jeśli mój serwer będzie nieosiągalny?
Google oczekuje kodu odpowiedzi stanu powodzenia HTTP 200 OK w przypadku SSV . Jeśli serwer jest nieosiągalny lub nie zapewnia , Google spróbuje ponownie wysłać wywołania zwrotne SSV maksymalnie 5 razy jednosekundowych odstępach.
Jak sprawdzić, czy wywołania zwrotne SSV pochodzą z Google?
Użyj wstecznego wyszukiwania DNS, by sprawdzić, czy wywołania zwrotne SSV pochodzą z Google.