I callback di verifica lato server sono richieste URL, con parametri di query espansi da Google, che vengono inviate da Google a un sistema esterno per segnalare che un utente deve essere premiato per interagire con un annuncio interstitial con premio o con premio. I callback SSV (Verifica lato server) con premio forniscono un ulteriore livello di protezione contro lo spoofing dei callback lato client per premiare gli utenti.
Questa guida mostra come verificare i callback SSV con premio utilizzando la libreria crittografica di terze parti delle app Tink Java per garantire che i parametri di query nel callback siano valori legittimi. Anche se Tink viene utilizzato ai fini della presente guida, hai la possibilità di utilizzare qualsiasi libreria di terze parti che supporti ECDSA. Puoi anche testare il server con lo strumento di test nell'interfaccia utente di AdMob.
Dai un'occhiata a questo esempio completamente funzionante utilizzando Java spring-boot.
Prerequisiti
Integra gli annunci con premio nella tua app per dispositivi mobili con Versione 7.28.0 o successiva dell'SDK Google Mobile Ads.
Attiva la verifica lato server con premio per l'unità pubblicitaria.
Utilizzare RewardAdsVerifier della libreria di app Java di Tink
Il repository GitHub delle app Java Tink
include una classe helper
RewardedAdsVerifier
per ridurre il codice necessario per verificare un callback SSV con premio.
L'utilizzo di questo corso consente di verificare un URL di callback con il codice seguente.
RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
.fetchVerifyingPublicKeysWith(
RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
.build();
String rewardUrl = ...;
verifier.verify(rewardUrl);
Se il metodo verify()
viene eseguito senza generare un'eccezione, l'URL di callback è stato verificato. La sezione Premiare l'utente descrive in dettaglio le best practice relative ai casi in cui gli utenti devono essere premiati. Per un'analisi dei passaggi eseguiti da questa classe per verificare i callback SSV con premio, puoi leggere la sezione Verifica manuale dell'SSV con premio.
Parametri callback SSV
I callback di verifica lato server contengono parametri di query che descrivono l'interazione con l'annuncio con premio. Di seguito sono elencati i nomi, le descrizioni e i valori di esempio dei parametri. I parametri vengono inviati in ordine alfabetico.
Nome parametro | Descrizione | Valore di esempio |
---|---|---|
ad_network | Identificatore dell'origine annuncio che ha soddisfatto questo annuncio. I nomi delle origini annuncio corrispondenti ai valori ID sono elencati nella sezione Identificatori delle origini annuncio. | 1953547073528090325 |
ad_unit | ID unità pubblicitaria AdMob utilizzato per richiedere l'annuncio con premio. | 2747237135 |
custom_data | Stringa di dati personalizzata fornita da
customRewardString
.
Se l'app non fornisce alcuna stringa di dati personalizzata, questo valore parametro di query non sarà presente nel callback SSV. |
SAMPLE_CUSTOM_DATA_STRING |
key_id | Chiave da utilizzare per verificare il callback SSV. Questo valore viene associato a una chiave pubblica fornita dal server chiavi AdMob. | 1234567890 |
reward_amount | L'importo del premio specificato nelle impostazioni dell'unità pubblicitaria. | 5 |
reward_item | Premio come specificato nelle impostazioni dell'unità pubblicitaria. | monete |
firma | Firma per il callback SSV generato da AdMob. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
timestamp | Timestamp in ms del momento in cui l'utente è stato premiato come tempo di epoca. | 1507770365237823 |
transaction_id | Identificatore univoco con codifica esadecimale per ogni evento di concessione di premi generato da AdMob. | 18fa792de1bca816048293fc71035638 |
user_id | Identificatore utente fornito da
userIdentifier .
Se l'app non fornisce alcun identificatore utente, questo parametro di query non sarà presente nel callback SSV. |
1234567 |
Identificatori delle origini annuncio
Nomi e ID delle origini annuncio
广告来源名称 | 广告来源 ID |
---|---|
Aarki(出价) | 5240798063227064260 |
Ad Generation(出价) | 1477265452970951479 |
AdColony | 15586990674969969776 |
AdColony(非 SDK)(出价) | 4600416542059544716 |
AdColony(出价) | 6895345910719072481 |
AdFalcon | 3528208921554210682 |
AdMob 广告联盟 | 5450213213286189855 |
ADResult | 10593873382626181482 |
AMoAd | 17253994435944008978 |
AppLovin | 1063618907739174004 |
AppLovin(出价) | 1328079684332308356 |
查特波斯特 | 2873236629771172317 |
Chocolate Platform(出价) | 6432849193975106527 |
跨渠道 (MdotM) | 9372067028804390441 |
自定义事件 | 18351550913290782395 |
DT Exchange* * 在 2022 年 9 月 21 日之前,该广告联盟称为“Fyber Marketplace”。 | 2179455223494392917 |
EMX(出价) | 8497809869790333482 |
Fluct(出价) | 8419777862490735710 |
小风 | 3376427960656545613 |
Fyber* * 此广告来源用于生成历史报告。 | 4839637394546996422 |
i-mobile | 5208827440166355534 |
优化数字化(出价) | 159382223051638006 |
Index Exchange(出价) | 4100650709078789802 |
InMobi | 7681903010231960328 |
InMobi(出价) | 6325663098072678541 |
IronSource | 6925240245545091930 |
ironSource Ads(出价) | 1643326773739866623 |
Leadbolt | 2899150749497968595 |
LG U+AD | 18298738678491729107 |
LINE 广告联盟 | 3025503711505004547 |
maio | 7505118203095108657 |
maio(出价) | 1343336733822567166 |
Media.net(出价) | 2127936450554446159 |
参与中介的自家广告 | 6060308706800320801 |
Meta Audience Network* * 在 2022 年 6 月 6 日之前,该广告联盟称为“Facebook Audience Network”。 | 10568273599589928883 |
Meta Audience Network(出价)* * 在 2022 年 6 月 6 日之前,该广告联盟称为“Facebook Audience Network(出价)”。 | 11198165126854996598 |
Mintegral | 1357746574408896200 |
Mintegral(出价) | 6250601289653372374 |
MobFox | 8079529624516381459 |
MobFox(出价) | 3086513548163922365 |
MoPub(已弃用) | 10872986198578383917 |
myTarget | 8450873672465271579 |
Nend | 9383070032774777750 |
Nexxen(出价)* * 在 2024 年 5 月 1 日之前,该广告联盟称为“UnrulyX”。 | 2831998725945605450 |
ONE by AOL (Millennial Media) | 6101072188699264581 |
ONE by AOL (Nexage) | 3224789793037044399 |
OneTag Exchange(出价) | 4873891452523427499 |
OpenX(出价) | 4918705482605678398 |
Pangle(出价) | 3525379893916449117 |
PubMatic(出价) | 3841544486172445473 |
预订型广告系列 | 7068401028668408324 |
RhythmOne(出价) | 2831998725945605450 |
Rubicon(出价) | 3993193775968767067 |
SK 星球 | 734341340207269415 |
Sharethrough(出价) | 5247944089976324188 |
Smaato(出价) | 3362360112145450544 |
Equativ(出价)* * 在 2023 年 1 月 12 日之前,该广告联盟称为“Smart Adserver”。 | 5970199210771591442 |
Sonobi(出价) | 3270984106996027150 |
Tapjoy | 7295217276740746030 |
Tapjoy(出价) | 4692500501762622178 |
Tencent GDT | 7007906637038700218 |
TripleLift(出价) | 8332676245392738510 |
Unity 广告 | 4970775877303683148 |
Unity Ads(出价) | 7069338991535737586 |
Verizon Media | 7360851262951344112 |
Verve Group(出价) | 5013176581647059185 |
弗蓬 | 1940957084538325905 |
Liftoff Monetize* * 在 2023 年 1 月 30 日之前,该广告联盟称为“Vungle”。 | 1953547073528090325 |
Liftoff Monetize(出价)* * 在 2023 年 1 月 30 日之前,该广告联盟称为“Vungle(出价)”。 | 4692500501762622185 |
Yieldmo(出价) | 4193081836471107579 |
YieldOne(出价) | 3154533971590234104 |
Zucks | 5506531810221735863 |
Premiare l'utente
Quando decidi quando premiare un utente, è importante trovare un equilibrio tra l'esperienza utente e la convalida del premio. I callback lato server potrebbero subire ritardi prima di raggiungere i sistemi esterni. Di conseguenza, la best practice consigliata prevede l'utilizzo del callback lato client per premiare immediatamente l'utente, eseguendo al contempo la convalida di tutti i premi al ricevimento dei callback lato server. Questo approccio offre una buona esperienza utente garantendo al contempo la validità dei premi concessi.
Tuttavia, per le applicazioni per cui la validità del premio è fondamentale (ad esempio, il premio influisce sull'economia in-game della tua app) e i ritardi nella concessione dei premi sono accettabili, attendere il callback lato server verificato potrebbe essere l'approccio migliore.
Dati personalizzati
Le app che richiedono dati aggiuntivi nei callback di verifica lato server devono usare la funzionalità dei dati personalizzati degli annunci con premio. Qualsiasi valore di stringa impostato su un oggetto annuncio con premio viene trasmesso al parametro di query custom_data
del callback SSV. Se non
è impostato alcun valore di dati personalizzati, il valore del parametro di query custom_data
non sarà
presente nel callback SSV.
Il seguente esempio di codice mostra come impostare le opzioni SSV dopo il caricamento dell'annuncio con premio.
Swift
GADRewardedAd.load(withAdUnitID:"ca-app-pub-3940256099942544/1712485313", request: request, completionHandler: { [self] ad, error in if let error != error { rewardedAd = ad let options = GADServerSideVerificationOptions() options.customRewardString = "SAMPLE_CUSTOM_DATA_STRING" rewardedAd.serverSideVerificationOptions = options }
Objective-C
GADRequest *request = [GADRequest request]; [GADRewardedAd loadWithAdUnitID:@"ca-app-pub-3940256099942544/1712485313" request:request completionHandler:^(GADRewardedAd *ad, NSError *error) { if (error) { // Handle Error return; } self.rewardedAd = ad; GADServerSideVerificationOptions *options = [[GADServerSideVerificationOptions alloc] init]; options.customRewardString = @"SAMPLE_CUSTOM_DATA_STRING"; ad.serverSideVerificationOptions = options; }];
Verifica manuale della verifica lato server con premio
Di seguito sono descritti i passaggi eseguiti dalla classe RewardedAdsVerifier
per verificare un
SSV con premio. Anche se gli snippet di codice inclusi sono in Java e utilizzano la libreria di terze parti Tink, puoi implementare questi passaggi nel linguaggio di tua scelta, utilizzando qualsiasi libreria di terze parti che supporti ECDSA.
Recupera chiavi pubbliche
Per verificare il callback SSV con premio, ti serve una chiave pubblica fornita da AdMob.
Un elenco di chiavi pubbliche da utilizzare per convalidare i callback SSV con premio può essere recuperato dal server chiavi AdMob. L'elenco di chiavi pubbliche viene fornito come rappresentazione JSON con un formato simile al seguente:
{
"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=="
},
],
}
Per recuperare le chiavi pubbliche, collegati al server chiavi AdMob e scarica le chiavi. Il codice seguente svolge questa attività e salva la rappresentazione JSON delle chiavi nella variabile 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();
}
Tieni presente che le chiavi pubbliche vengono ruotate regolarmente. Riceverai un'email che ti informa della prossima rotazione. Se memorizzi nella cache le chiavi pubbliche, ti consigliamo di aggiornarle alla ricezione di questa email.
Una volta recuperate, le chiavi pubbliche devono essere analizzate. Il metodo parsePublicKeysJson
di seguito prende come input una stringa JSON, come nell'esempio precedente, e crea una mappatura dai valori key_id
alle chiavi pubbliche, che vengono incapsulate come oggetti ECPublicKey
dalla libreria 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;
}
Richiedi la verifica dei contenuti
Gli ultimi due parametri di query dei callback SSV con premio sono sempre signature
e key_id,
in questo ordine. I restanti parametri di query specificano i contenuti
da verificare. Supponiamo che tu abbia configurato AdMob per inviare callback dei premi a https://www.myserver.com/mypath
. Lo snippet riportato di seguito mostra un esempio di callback SSV con premio, in cui sono evidenziati i contenuti da verificare.
https://www.myserver.com/path?ad_network=54...55&ad_unit=12345678&reward_amount=10&reward_item=coins ×tamp=150777823&transaction_id=12...DEF&user_id=1234567&signature=ME...Z1c&key_id=1268887
Il codice seguente mostra come analizzare i contenuti da verificare da un URL di callback come array UTF-8 byte.
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"));
Ottieni la firma e il key_id dall'URL di callback
Utilizzando il valore queryString
del passaggio precedente, analizza i parametri di query signature
e
key_id
dell'URL di callback come mostrato di seguito:
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()));
Esegui la verifica
Il passaggio finale consiste nel verificare i contenuti dell'URL di callback con la chiave pubblica appropriata. Recupera la mappatura restituita dal metodo parsePublicKeysJson
e utilizza il parametro key_id
dall'URL di callback per ottenere la chiave pubblica da quella mappatura. Poi verifica la firma con
quella chiave pubblica. Questi passaggi sono mostrati di seguito nel metodo 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);
}
}
Se il metodo viene eseguito senza generare un'eccezione, l'URL di callback è stato verificato.
Domande frequenti
- Posso memorizzare nella cache la chiave pubblica fornita dal server chiavi di AdMob?
- Ti consigliamo di memorizzare nella cache la chiave pubblica fornita dal server chiavi di AdMob per ridurre il numero di operazioni necessarie per convalidare i callback SSV. Tuttavia, tieni presente che le chiavi pubbliche vengono ruotate regolarmente e non devono essere memorizzate nella cache per più di 24 ore.
- Con quale frequenza vengono ruotate le chiavi pubbliche fornite dal server chiavi di AdMob?
- Le chiavi pubbliche fornite dal server chiavi di AdMob vengono ruotate in base a una pianificazione delle variabili. Per garantire che la verifica dei callback SSV continui a funzionare come previsto, le chiavi pubbliche non devono essere memorizzate nella cache per più di 24 ore.
- Che cosa succede se il mio server non può essere raggiunto?
- Google prevede un codice di risposta dello stato di operazione riuscita
HTTP 200 OK
per i callback SSV. Se il tuo server non può essere raggiunto o non fornisce la risposta prevista, Google tenterà nuovamente di inviare callback SSV fino a cinque volte a intervalli di un secondo. - Come faccio a verificare che le richiamate SSV provengano da Google?
- Usa la ricerca DNS inversa per verificare che i callback SSV provengano da Google.