Callbacks für serverseitige Überprüfungen validieren

Bei serverseitigen Callbacks für die Überprüfung handelt es sich um URL-Anfragen mit von Google erweiterten Suchparametern, die von Google an ein externes System gesendet werden, um darüber zu informieren, dass Nutzer für die Interaktion mit einer Interstitial-Anzeige mit Prämie oder Anzeigen mit Prämie eine Prämie erhalten sollen. Callbacks für die serverseitige Überprüfung von Anzeigen mit Prämie bieten einen zusätzlichen Schutz vor Spoofing clientseitiger Callbacks, um Nutzer zu belohnen.

In diesem Leitfaden erfahren Sie, wie Sie SSV-Callbacks mit Prämie mithilfe der kryptografischen Bibliothek eines Drittanbieters mit Tink Java Apps verifizieren, damit die Abfrageparameter im Callback legitime Werte sind. Obwohl Tink für die Zwecke dieser Anleitung verwendet wird, können Sie jede Drittanbieterbibliothek verwenden, die ECDSA unterstützt. Sie können Ihren Server auch mit dem Testtool in der AdMob-Benutzeroberfläche testen.

Dieses voll funktionsfähige Beispiel, in dem Java-Springboot verwendet wird

Voraussetzungen

RewardAdsVerifier aus der Tink Java Apps-Bibliothek verwenden

Das GitHub-Repository für Tink-Java-Apps enthält eine RewardedAdsVerifier-Hilfsklasse, mit der sich der Code für die Prüfung eines SSV-Callbacks mit Prämie reduzieren lässt. Mithilfe dieser Klasse können Sie eine Rückruf-URL mit dem folgenden Code verifizieren.

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

Wenn die Methode verify() ohne Ausnahme ausgeführt wird, wurde die Callback-URL erfolgreich bestätigt. Im Abschnitt Nutzer belohnen sind Best Practices dazu aufgeführt, wann Nutzer eine Prämie erhalten sollten. Eine Aufschlüsselung der Schritte, die von dieser Klasse ausgeführt werden, um SSV-Callbacks mit Prämie zu überprüfen, finden Sie im Abschnitt Manuelle Überprüfung von SSV-Callbacks mit Prämie.

Callback-Parameter für SSV

Callbacks für die serverseitige Überprüfung enthalten Abfrageparameter, die die Interaktion mit Anzeigen mit Prämie beschreiben. Parameternamen, Beschreibungen und Beispielwerte sind unten aufgeführt. Parameter werden in alphabetischer Reihenfolge gesendet.

Parametername Beschreibung Beispielwert
ad_network Die ID der Anzeigenquelle der Anzeigenquelle, über die diese Anzeige ausgeliefert wurde. Die Namen von Anzeigenquellen, die den ID-Werten entsprechen, sind im Abschnitt Kennungen der Anzeigenquelle aufgeführt. 1953547073528090325
ad_unit Die ID des AdMob-Anzeigenblocks, über den die Anzeige mit Prämie angefordert wurde. 2747237135
custom_data Benutzerdefinierter Datenstring wie bereitgestellt von .

Wenn von der Anwendung kein benutzerdefinierter Datenstring bereitgestellt wird, ist dieser Abfrageparameterwert nicht im SSV-Callback vorhanden.

SAMPLE_CUSTOM_DATA_STRING
key_id Schlüssel, der zur Bestätigung des Rückrufs der SSV verwendet werden soll. Dieser Wert ist einem öffentlichen Schlüssel zugeordnet, der vom AdMob-Schlüsselserver bereitgestellt wird. 1234567890
reward_amount Prämienbetrag wie in den Anzeigenblockeinstellungen angegeben. 5
reward_item Prämienartikel gemäß den Angaben in den Anzeigenblockeinstellungen. Münzen
Signatur Signatur für SSV-Rückruf, der von AdMob generiert wird. MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY
timestamp Zeitstempel in ms, der angibt, wann der Nutzer eine Prämie erhalten hat. 1507770365237823
transaction_id Eindeutige hex-codierte Kennung für jedes von AdMob generierte Prämien-Grant-Ereignis. 18fa792de1bca816048293fc71035638
user_id Nutzer-ID von SetUserId.

Wenn von der Anwendung keine Nutzerkennung bereitgestellt wird, ist dieser Abfrageparameter nicht im SSV-Callback vorhanden.

1234567

Anzeigenquellen-IDs

Namen und IDs der Anzeigenquellen

Name der Anzeigenquelle ID der Anzeigenquelle
Aarki (Gebote)5240798063227064260
Anzeigengenerierung (Bidding)1477265452970951479
AdColony15586990674969969776
AdColony (kein SDK) (Bidding)4600416542059544716
AdColony (Bidding)6895345910719072481
AdFalcon3528208921554210682
AdMob-Werbenetzwerk5450213213286189855
ADResult10593873382626181482
AMoAd17253994435944008978
Applovin1063618907739174004
Applovin (Bidding)1328079684332308356
Chartboost2873236629771172317
Chocolate Platform (Bidding)6432849193975106527
Kanalübergreifend (MdotM)9372067028804390441
Benutzerdefiniertes Ereignis18351550913290782395
DT Exchange*
* Vor dem 21. September 2022 hieß dieses Netzwerk „Fyber Marketplace“.
2179455223494392917
EMX (Bidding)8497809869790333482
Schwankt (Gebote)8419777862490735710
Windböen3376427960656545613
Fyber*
* Diese Anzeigenquelle wird für Berichte mit bisherigen Daten verwendet.
4839637394546996422
i-mobile5208827440166355534
Digitale Kampagnen optimieren (Bidding)159382223051638006
Index Exchange (Bidding)4100650709078789802
InMobi7681903010231960328
InMobi (Bidding)6325663098072678541
IronSource6925240245545091930
Leadbolt2899150749497968595
LG U+AD18298738678491729107
LINE-Werbenetzwerk3025503711505004547
maio7505118203095108657
Maio (Bidding)1343336733822567166
Media.net (Bidding)2127936450554446159
Vermittelte hausinterne Anzeigen6060308706800320801
Meta Audience Network*
* Vor dem 6. Juni 2022 hieß dieses Netzwerk „Facebook Audience Network“.
10568273599589928883
Meta Audience Network (Bidding)*
* Vor dem 6. Juni 2022 hieß dieses Netzwerk „Facebook Audience Network (Bidding)“.
11198165126854996598
Mintegral1357746574408896200
Mintegral (Bidding)6250601289653372374
MobFox8079529624516381459
MobFox (Bidding)3086513548163922365
MoPub (eingestellt)10872986198578383917
myTarget8450873672465271579
Nend9383070032774777750
Nexxen (Bidding)*

* Vor dem 1. Mai 2024 hieß dieses Netzwerk „UnrulyX“.

2831998725945605450
ONE by AOL (Millennial Media)6101072188699264581
ONE by AOL (Nexage)3224789793037044399
OneTag Exchange (Bidding)4873891452523427499
OpenX (Bidding)4918705482605678398
Pangle (Bidding)3525379893916449117
PubMatic (Bidding)3841544486172445473
Reservierungskampagne7068401028668408324
RhythmOne (Bidding)2831998725945605450
Rubicon (Bidding)3993193775968767067
SK Planet734341340207269415
Sharethrough (Bidding)5247944089976324188
Smaato (Bidding)3362360112145450544
Equativ (Bidding)*

* Vor dem 12. Januar 2023 hieß dieses Netzwerk „Smart Ad-Server“.

5970199210771591442
Sonobi (Bidding)3270984106996027150
Tapjoy7295217276740746030
Tapjoy (Bidding)4692500501762622178
Tencent GDT7007906637038700218
TripleLift (Bidding)8332676245392738510
Unity-Anzeigen4970775877303683148
Verizon Media7360851262951344112
Verve-Gruppe (Bidding)5013176581647059185
Vpon1940957084538325905
Liftoff – Monetarisieren*

* Vor dem 30. Januar 2023 hieß dieses Netzwerk „Vungle“.

1953547073528090325
Liftoff – monetarisieren (Bidding)*

* Vor dem 30. Januar 2023 hieß dieses Werbenetzwerk „Vungle (Bidding)“.

4692500501762622185
Yieldmo (Bidding)4193081836471107579
YieldOne (Bidding)3154533971590234104
Zicken5506531810221735863

Belohnen der Nutzenden

Bei der Entscheidung, wann ein Nutzer belohnt wird, ist es wichtig, ein ausgewogenes Verhältnis zwischen Nutzererfahrung und Validierung der Belohnung zu haben. Bei serverseitigen Callbacks kann es zu Verzögerungen kommen, bevor externe Systeme erreicht werden. Daher wird empfohlen, den clientseitigen Callback zu verwenden, um den Nutzer sofort zu belohnen, während bei serverseitigen Callbacks alle Prämien geprüft werden. Dieser Ansatz sorgt für eine gute Nutzerfreundlichkeit und sorgt gleichzeitig dafür, dass die gewährten Prämien gültig bleiben.

Bei Anwendungen, bei denen die Gültigkeit der Prämie jedoch von entscheidender Bedeutung ist (z. B. die Prämie wirkt sich auf die In-Game-Ökonomie Ihrer App aus) und bei denen Verzögerungen bei der Vergabe von Prämien akzeptabel sind, ist es am besten, auf den verifizierten serverseitigen Callback zu warten.

Benutzerdefinierte Daten

Apps, die zusätzliche Daten in serverseitigen Bestätigungs-Callbacks erfordern, sollten die Funktion für benutzerdefinierte Daten von Anzeigen mit Prämie verwenden. Jeder Stringwert, der für ein Objekt für Anzeigen mit Prämie festgelegt wurde, wird an den Abfrageparameter custom_data des SSV-Callbacks übergeben. Wenn kein benutzerdefinierter Datenwert festgelegt ist, ist der Wert des Abfrageparameters custom_data nicht im SSV-Callback enthalten.

Im folgenden Codebeispiel wird gezeigt, wie die Optionen für die serverseitige Überprüfung festgelegt werden, nachdem die Anzeige mit Prämie geladen wurde.

void HandleRewardedAdLoaded(RewardedAd ad, AdFailedToLoadEventArgs error)
{
    // Create and pass the SSV options to the rewarded ad.
    var options = new ServerSideVerificationOptions
                          .Builder()
                          .SetCustomData("SAMPLE_CUSTOM_DATA_STRING")
                          .Build()
    ad.SetServerSideVerificationOptions(options);
}

Wenn Sie den benutzerdefinierten Prämienstring festlegen möchten, müssen Sie dies tun, bevor die Anzeige ausgeliefert wird.

Manuelle Überprüfung der SSV mit Prämie

Im Folgenden sind die Schritte aufgeführt, die von der Klasse RewardedAdsVerifier ausgeführt werden, um eine SSV mit Prämie zu prüfen. Obwohl die enthaltenen Code-Snippets in Java geschrieben sind und die Tink-Bibliothek des Drittanbieters nutzen, können diese Schritte von Ihnen in der Sprache Ihrer Wahl implementiert werden. Verwenden Sie dazu eine beliebige Drittanbieterbibliothek, die ECDSA unterstützt.

Öffentliche Schlüssel abrufen

Wenn Sie einen SSV-Callback mit Prämie bestätigen möchten, benötigen Sie einen von AdMob bereitgestellten öffentlichen Schlüssel.

Auf dem AdMob-Schlüsselserver finden Sie eine Liste der öffentlichen Schlüssel, mit denen die SSV-Callbacks mit Prämie validiert werden können. Die Liste der öffentlichen Schlüssel wird als JSON-Darstellung in einem Format wie dem folgenden bereitgestellt:

{
 "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=="
    },
  ],
}

Stellen Sie eine Verbindung zum AdMob-Schlüsselserver her und laden Sie die Schlüssel herunter, um die öffentlichen Schlüssel abzurufen. Mit dem folgenden Code wird diese Aufgabe ausgeführt und die JSON-Darstellung der Schlüssel in der Variable data gespeichert.

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();
}

Beachten Sie, dass öffentliche Schlüssel regelmäßig rotiert werden. Sie werden per E-Mail über eine bevorstehende Rotation informiert. Wenn Sie öffentliche Schlüssel im Cache speichern, sollten Sie die Schlüssel nach Erhalt dieser E-Mail aktualisieren.

Sobald die öffentlichen Schlüssel abgerufen wurden, müssen sie geparst werden. Die Methode parsePublicKeysJson unten verwendet einen JSON-String wie im obigen Beispiel als Eingabe und erstellt eine Zuordnung von key_id-Werten zu öffentlichen Schlüsseln, die als ECPublicKey-Objekte aus der Tink-Bibliothek gekapselt sind.

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

Inhalte überprüfen lassen

Die letzten beiden Abfrageparameter von SSV-Callbacks mit Prämie sind immer signature und key_id, in dieser Reihenfolge. Die verbleibenden Abfrageparameter geben den zu überprüfenden Inhalt an. Angenommen, Sie haben AdMob so konfiguriert, dass Callbacks für Prämien an https://www.myserver.com/mypath gesendet werden. Das folgende Snippet zeigt ein Beispiel für einen SSV-Callback mit Prämie, bei dem der zu bestätigende Inhalt hervorgehoben wird.

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

Der folgende Code zeigt, wie der zu überprüfende Inhalt von einer Callback-URL als UTF-8-Byte-Array geparst wird.

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

Signatur und key_id von Callback-URL abrufen

Verwenden Sie den Wert queryString aus dem vorherigen Schritt, um die Abfrageparameter signature und key_id aus der Callback-URL wie unten gezeigt zu parsen:

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()));

Bestätigung durchführen

Im letzten Schritt wird der Inhalt der Callback-URL mit dem entsprechenden öffentlichen Schlüssel überprüft. Verwenden Sie die von der Methode parsePublicKeysJson zurückgegebene Zuordnung und den Parameter key_id der Callback-URL, um den öffentlichen Schlüssel aus dieser Zuordnung zu erhalten. Überprüfen Sie dann die Signatur mit diesem öffentlichen Schlüssel. Diese Schritte werden unten in der Methode verify beschrieben.

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

Wenn die Methode ohne Ausnahme ausgeführt wird, wurde die Callback-URL erfolgreich verifiziert.

Häufig gestellte Fragen

Kann ich den vom AdMob-Schlüsselserver bereitgestellten öffentlichen Schlüssel im Cache speichern?
Wir empfehlen, den vom AdMob-Schlüsselbund bereitgestellten öffentlichen Schlüssel im Cache zu speichern, um die Anzahl der Vorgänge zum Validieren von SSV-Callbacks zu reduzieren. Beachten Sie jedoch, dass öffentliche Schlüssel regelmäßig rotiert werden und nicht länger als 24 Stunden im Cache gespeichert werden sollten.
Wie oft werden die vom AdMob-Schlüsselserver bereitgestellten öffentlichen Schlüssel rotiert?
Öffentliche Schlüssel, die vom AdMob-Schlüsselserver bereitgestellt werden, werden nach einem variablen Zeitplan rotiert. Damit die Überprüfung von SSV-Callbacks weiterhin wie gewünscht funktioniert, sollten öffentliche Schlüssel nicht länger als 24 Stunden im Cache gespeichert werden.
Was passiert, wenn mein Server nicht erreichbar ist?
Google erwartet für SSV-Callbacks einen Antwortcode für den Erfolgsstatus HTTP 200 OK. Wenn Ihr Server nicht erreichbar ist oder nicht die erwartete Antwort zurückgibt, versucht Google noch einmal, SSV-Rückrufe bis zu fünfmal in 1-Sekunden-Intervallen zu senden.
Wie kann ich überprüfen, ob SSV-Rückrufe von Google stammen?
Mit dem umgekehrten DNS-Lookup können Sie prüfen, ob SSV-Callbacks von Google stammen.