Zweryfikuj wywołania zwrotne weryfikacji po stronie serwera (SSV)

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

Wywołania zwrotne po stronie serwera to żądania adresów URL z rozwiniętymi parametrami zapytań, które są wysyłane przez Google do systemów zewnętrznych, aby powiadomić użytkowników, że powinni otrzymać nagrodę za interakcję z reklamą pełnoekranową z nagrodą. Wywołania zwrotne z nagrodą SSV (weryfikacja po stronie serwera) zapewniają dodatkową warstwę ochrony przed podszywaniem się po stronie klienta w celu wynagrodzenia użytkowników.

W tym przewodniku pokazujemy, jak zweryfikować wywołania zwrotne SSV z nagrodą za pomocą biblioteki kryptograficznej Tink innej firmy, aby mieć pewność, że parametry zapytania w wywołaniach zwrotnych są prawidłowe. Mimo że Tink jest używany na potrzeby tego przewodnika, możesz używać dowolnej biblioteki innej firmy, która obsługuje ECDSA. Możesz też przetestować serwer za pomocą narzędzia do testowania w interfejsie AdMob.

Zapoznaj się z tym w pełni działającym przykładem, używając wiosennego rozruchu Java.

Wymagania wstępne

Korzystanie z reklamy RewardedAdsVerifier od Tink

Repozytorium Tink na GitHubie zawiera klasę pomocniczą RewardedAdsVerifier, która zmniejsza kod wymagany do weryfikacji wywołania zwrotnego SSV. Użycie tej klasy do obsługi biblioteki kryptograficznej Tink innej firmy pozwala zweryfikować 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() uruchamia się bez zgłaszania wyjątku, adres URL wywołania zwrotnego został zweryfikowany. W sekcji Nagroda dla użytkownika znajdziesz sprawdzone metody, które określają, kiedy należy nagradzać użytkowników. Informacje o czynnościach, które wykonuje się w ramach tej klasy, by zweryfikować wywołania zwrotne SSV z nagrodą, znajdziesz w sekcji Weryfikacja manualna w przypadku reklam SSV.

Parametry wywołania zwrotnego SSV

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

Nazwa parametru Opis Przykładowa wartość
sieć_reklamowa Identyfikator źródła reklam, które wypełniło tę reklamę. Nazwy źródeł reklam odpowiadające wartościom identyfikatora są wymienione w sekcji Identyfikatory źródła reklam. 1953547073528090325
ad_unit, Identyfikator jednostki reklamowej AdMob użyty do wysłania żądania reklamy z nagrodą. 2747237135
dane_niestandardowe Niestandardowy ciąg danych podany przez: setCustomData .

Jeśli aplikacja nie dostarczy niestandardowego ciągu danych, wartość tego parametru zapytania nie będzie podana w wywołaniu SSV.

SAMPLE_CUSTOM_DATA_STRING
identyfikator_klucza Klucz używany do weryfikowania wywołania zwrotnego SSV. Ta wartość jest mapowana na klucz publiczny udostępniony przez serwer kluczy AdMob. 1234567890
kwota_nagrody Kwota nagrody określona w ustawieniach jednostki reklamowej. 5
element_nagrody Element nagrody jest określony w ustawieniach jednostki reklamowej. monety
podpis Podpis wywołania zwrotnego SSV wygenerowanego przez AdMob. MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY
sygnatura czasowa Sygnatura czasowa momentu, w którym użytkownik miał otrzymać nagrodę w czasach epoki (w ms). 1507770365237823
transaction_id Unikalny zakodowany szesnastkowo identyfikator każdego zdarzenia przyznania nagrody wygenerowany przez AdMob. 18fa792de1bca816048293fc71035638
user_id Identyfikator użytkownika podany przez setUserId.

Jeśli aplikacja nie poda identyfikatora użytkownika, ten parametr zapytania nie będzie występować w wywołaniu 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 (określanie stawek)1477265452970951479
AdColony15586990674969969776
AdColony (nie SDK) (określanie stawek)4600416542059544716
AdColony (określanie stawek)6895345910719072481
AdFalcon3528208921554210682
Sieć AdMob5450213213286189855
AD wyniku10593873382626181482
ReklamaMoMo17253994435944008978
AppLovin1063618907739174004
Applovin (określanie stawek)1328079684332308356
Grafboost2873236629771172317
Czekolada z platformą (określanie stawek)6432849193975106527
W różnych kanałach (MdotM)9372067028804390441
Zdarzenie niestandardowe18351550913290782395
DT Exchange
Przed 21 września 2022 roku ta sieć nazywała się „Fyber”.
4839637394546996422
Wahania (określanie stawek)8419777862490735710
Pochmurno3376427960656545613
i-mobile5208827440166355534
Ulepszanie rozwiązań cyfrowych (określanie stawek)159382223051638006
Giełda indeksowa (określanie stawek)4100650709078789802
InMobi7681903010231960328
InMobi (określanie stawek)6325663098072678541
Źródło Iron6925240245545091930
Leadbolt2899150749497968595
LG U+AD18298738678491729107
Maio7505118203095108657
maio (określanie stawek)1343336733822567166
Media.net (określanie stawek)2127936450554446159
Zapośredniczone autoreklamy6060308706800320801
Meta Audience Network
Przed 6 czerwca 2022 roku ta sieć nosiła nazwę „Facebook Audience Network”.
10568273599589928883
Meta Audience Network (określanie stawek)
Przed 6 czerwca 2022 roku ta sieć nosiła nazwę „Facebook Audience Network (bidding)”.
11198165126854996598
MobFox8079529624516381459
MoPub (wycofane)10872986198578383917
mój_cel8450873672465271579
Nend9383070032774777750
ONE by AOL (Millennial Media)6101072188699264581
ONE by AOL (Nexage)3224789793037044399
OpenX (określanie stawek)4918705482605678398
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 K734341340207269415
Udostępnianie (określanie stawek)5247944089976324188
Smaato (określanie stawek)3362360112145450544
Equativ (określanie stawek)*

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

5970199210771591442
Sonobi (określanie stawek)3270984106996027150
Tapjoy7295217276740746030
Tapjoy (określanie stawek)4692500501762622178
Tencent GDT7007906637038700218
TripleLift (określanie stawek)8332676245392738510
Reklamy Unity4970775877303683148
UnrulyX (określanie stawek)2831998725945605450
Verizon Media7360851262951344112
Vpon1940957084538325905
Zakończenie zarabiania*

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

1953547073528090325
Rozpoczęcie zarabiania (określanie stawek)*

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

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

Nagradzanie użytkowników

Podczas podejmowania decyzji o nagrodzie należy wziąć pod uwagę równowagę między wrażeniami użytkowników a weryfikacją nagród. Wywołania zwrotne po stronie serwera mogą być opóźnione przed dotarciem do systemów zewnętrznych. Dlatego zalecamy stosowanie metody zwrotnej po stronie klienta w celu natychmiastowego nagradzania użytkownika i sprawdzania wszystkich nagród po otrzymaniu wywołań po stronie serwera. Takie podejście zapewnia użytkownikom dobre wrażenia, a jednocześnie powoduje, że przyznane nagrody są prawidłowe.

W przypadku aplikacji, których ważność jest ważna (np. nagroda ma wpływ na gospodarkę w aplikacji), a jej opóźnienia w realizacji nagród są dozwolone.

Dane niestandardowe

Aplikacje, które wymagają dodatkowych danych w wywołaniach weryfikacji po stronie serwera, powinny korzystać z niestandardowej funkcji danych z reklamami z nagrodą. Każda wartość ciągu ustawiona w obiekcie reklamy z nagrodą jest przekazywana do parametru zapytania custom_data wywołania zwrotnego SSV. Jeśli nie ustawisz żadnej niestandardowej wartości danych, wartość parametru zapytania custom_data nie będzie podana w wywołaniu zwrotnym SSV.

Poniższy przykładowy kod pokazuje, jak ustawić opcje weryfikacji po wyświetleniu reklamy z nagrodą.

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 nagród, musisz to zrobić przed wyświetleniem reklamy.

Weryfikacja ręczna w przypadku reklam SSV

Czynności wykonywane w klasie RewardedAdsVerifier w celu weryfikacji reklamy TrueView z nagrodą są opisane poniżej. Uwzględnione fragmenty kodu są w języku Java i korzystają z biblioteki Tink firmy zewnętrznej, ale możesz wykonać te kroki w wybranym przez siebie języku, używając dowolnej biblioteki zewnętrznej, która obsługuje ECDSA.

Pobieranie kluczy publicznych

Aby zweryfikować wywołanie zwrotne SSV z nagrodą, musisz mieć klucz publiczny udostępniony przez AdMob.

Lista kluczy publicznych, które mają służyć do weryfikowania wywołań zwrotnych SSV z nagrodą, można pobrać z serwera kluczy AdMob. Lista kluczy publicznych jest wyświetlana w formacie 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 klucze. Poniższy kod wykonuje to zadanie i zapisuje przedstawienie kluczy w zmiennej JSON w 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();
}

Klucze publiczne są regularnie poddawane rotacji. Otrzymasz e-maila z informacją o zbliżającym się rotacji. Jeśli przechowujesz w pamięci podręcznej klucze publiczne, musisz zaktualizować klucze po otrzymaniu tego e-maila.

Po pobraniu kluczy publicznych muszą zostać przeanalizowane. Metoda parsePublicKeysJson poniżej wykorzystuje ciąg JSON (jak w przykładzie powyżej) i tworzy mapowanie z wartości key_id do kluczy publicznych, które są przekształcane w 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;
}

Pobierz treści do weryfikacji

Ostatnie 2 parametry zapytania z wywołaniem SSV z nagrodą to zawsze signature i key_id, w tej kolejności. Pozostałe parametry zapytania określają zawartość strony, która ma zostać zweryfikowana. Załóżmy, że masz skonfigurowane w AdMob wysyłanie wywołań zwrotnych do https://www.myserver.com/mypath. Fragment kodu poniżej pokazuje przykładowego wywołania zwrotnego reklamy z nagrodą z wyróżnioną treścią.

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ść do weryfikacji z adresu URL wywołania zwrotnego jako tablicę 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"));

Uzyskiwanie podpisu i klucza_identyfikatora z adresu URL wywołania zwrotnego

Korzystając z wartości queryString z poprzedniego kroku, przeanalizuj parametry zapytania signature i 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ę

Na koniec należy zweryfikować treść adresu URL wywołania zwrotnego za pomocą odpowiedniego klucza publicznego. Zmapuj zwracane dane z metody parsePublicKeysJson i użyj parametru key_id z adresu URL wywołania zwrotnego, aby uzyskać klucz publiczny z tego mapowania. Następnie sprawdź podpis przy użyciu tego klucza publicznego. Podane niżej kroki zostały przedstawione 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 działa bez wyjątku, adres URL wywołania zwrotnego został zweryfikowany.

Najczęstsze pytania

Czy mogę buforować klucz publiczny udostępniony przez serwer kluczy AdMob?
Zalecamy przechowywanie w pamięci podręcznej klucza publicznego podanego przez serwer kluczy AdMob, aby zmniejszyć liczbę operacji wymaganych do weryfikacji wywołań zwrotnych SSV. Pamiętaj jednak, że klucze publiczne są regularnie rotowane i nie powinny być przechowywane w pamięci podręcznej dłużej niż 24 godziny.
Jak często są aktualizowane klucze publiczne dostarczane przez serwer kluczy AdMob?
Klucze publiczne udostępnione przez serwer kluczy AdMob są poddawane rotacji zgodnie ze harmonogramem. Aby sprawdzić, czy wywołania zwrotne usługi SSV nadal działają zgodnie z oczekiwaniami, klucze publiczne nie powinny być przechowywane w pamięci podręcznej dłużej niż 24 godziny.
Co się stanie, jeśli mój serwer nie zostanie połączony?
Google spodziewa się HTTP 200 OK kodu odpowiedzi stanu wywołania zwrotnego SSV. Jeśli nie uda się nawiązać połączenia z serwerem lub nie uzyskasz oczekiwanej odpowiedzi, Google ponownie spróbuje wysłać wywołanie zwrotne SSV maksymalnie 5-krotnie w sekundach.
Jak sprawdzić, czy wywołania zwrotne usługi SSV pochodzą od Google?
Użyj odwrotnego wyszukiwania DNS, aby sprawdzić, czy wywołania zwrotne SSV pochodzą od Google.