Les rappels de validation côté serveur sont des requêtes d'URL avec des paramètres de requête développés par Google, envoyés par Google vers un système externe l'informer qu'un utilisateur doit être récompensé pour avoir interagi avec un une annonce interstitielle avec récompense. Rappels de validation côté serveur (SSV) avec récompense offrent un niveau de protection supplémentaire contre le spoofing des rappels côté client. pour récompenser les utilisateurs.
Ce guide vous explique comment vérifier les rappels de validation côté serveur avec récompense à l'aide du Applications tierces Tink Java cryptographique pour garantir que les paramètres de requête du rappel sont des valeurs légitimes. Bien que Tink soit utilisé pour les besoins de ce guide, vous avez la possibilité utiliser toute bibliothèque tierce compatible ECDSA : Vous pouvez également tester votre serveur à l'aide de la fonction dans l'interface utilisateur d'AdMob.
Consultez cette page entièrement fonctionnelle exemple à l'aide du Spring-boot Java.
Prérequis
Intégrez des annonces avec récompense dans votre application mobile avec v11.6.0 ou version ultérieure du SDK Google Mobile Ads.
Activer les récompenses côté serveur de validation sur votre bloc d'annonces.
Utiliser RécompenseAdsVerifier à partir de la bibliothèque d'applications Java Tink
Le dépôt GitHub des applications Java Tink
inclut un
RewardedAdsVerifier
pour réduire le code requis pour valider un rappel de validation côté serveur avec récompense.
L'utilisation de cette classe vous permet de vérifier une URL de rappel à l'aide du code suivant.
RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
.fetchVerifyingPublicKeysWith(
RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
.build();
String rewardUrl = ...;
verifier.verify(rewardUrl);
Si la méthode verify()
s'exécute sans générer d'exception, le rappel
L'URL a bien été vérifiée. L'option Récompenser l'utilisateur
détaille les bonnes pratiques concernant le moment où les utilisateurs doivent recevoir des récompenses. Pour une
la répartition des étapes réalisées par cette classe pour vérifier les rappels de validation côté serveur avec récompense ;
consultez l'article Validation manuelle des annonces avec récompense
SSV.
Paramètres de rappel SSV
Les rappels de validation côté serveur contiennent des paramètres de requête qui décrivent sur l'interaction avec une annonce avec récompense. Les noms, descriptions et exemples de valeurs des paramètres comme indiqué ci-dessous. Les paramètres sont envoyés par ordre alphabétique.
Nom du paramètre | Description | Exemple de valeur |
---|---|---|
ad_network | Identifiant de la source d'annonces qui a généré cette annonce. Source des annonces les noms correspondant aux valeurs des identifiants sont répertoriés dans la section les identifiants sources. | 1953547073528090325 |
ad_unit | ID du bloc d'annonces AdMob utilisé pour demander l'annonce avec récompense. | 2747237135 |
custom_data | Chaîne de données personnalisée fournie par
<ph type="x-smartling-placeholder"></ph>
setCustomData
Si aucune chaîne de données personnalisée n'est fournie par l'application, ce paramètre de requête ne sera pas présente dans le rappel de validation côté serveur. |
SAMPLE_CUSTOM_DATA_STRING |
key_id | Clé à utiliser pour vérifier le rappel SSV. Cette valeur correspond à une clé publique fournies par le serveur de clés AdMob. | 1234567890 |
reward_amount | Montant de la récompense tel que spécifié dans les paramètres du bloc d'annonces. | 5 |
reward_item | Élément de récompense tel que spécifié dans les paramètres du bloc d'annonces. | pièces |
signature | Signature pour le rappel SSV généré par AdMob. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
timestamp | Horodatage en millisecondes du moment où l'utilisateur a été récompensé. | 1507770365237823 |
transaction_id | Identifiant unique encodé en hexadécimal pour chaque événement d'attribution de récompense généré par AdMob. | 18fa792de1bca816048293fc71035638 |
user_id | Identifiant utilisateur fourni par
setUserId
Si aucun identifiant utilisateur n'est fourni par l'application, ce paramètre de requête ne être présentes dans le rappel SSV. |
1234567 |
Identifiants de sources d'annonces
Noms et ID des sources d'annonces
Nom de la source de l'annonce | ID de la source d'annonces |
---|---|
Aarki (enchères) | 5240798063227064260 |
Ad Generation (enchères) | 1477265452970951479 |
AdColony | 15586990674969969776 |
AdColony (hors SDK) (enchères) | 4600416542059544716 |
AdColony (enchères) | 6895345910719072481 |
AdFalcon | 3528208921554210682 |
Réseau AdMob | 5450213213286189855 |
Cascade d'annonces du réseau AdMob | 1215381445328257950 |
ADResult | 10593873382626181482 |
AMoAd | 17253994435944008978 |
Applovine | 1063618907739174004 |
Applovin (enchères) | 1328079684332308356 |
Chartboost | 2873236629771172317 |
Chocolate Platform (enchères) | 6432849193975106527 |
CrossChannel (MdotM) | 9372067028804390441 |
Événement personnalisé | 18351550913290782395 |
DT Exchange* * Avant le 21 septembre 2022, ce réseau s'appelait "Fyber Marketplace". | 2179455223494392917 |
EMX (enchères) | 8497809869790333482 |
Fluct (enchères) | 8419777862490735710 |
Bourrasques | 3376427960656545613 |
Fyber* * Cette source d'annonces est utilisée pour l'historique des rapports. | 4839637394546996422 |
i-mobile | 5208827440166355534 |
Improve Digital (enchères) | 159382223051638006 |
Place de marché d'index (enchères) | 4100650709078789802 |
InMobi | 7681903010231960328 |
InMobi (enchères) | 6325663098072678541 |
InMobi Exchange (enchères) | 5264320421916134407 |
IronSource | 6925240245545091930 |
ironSource Ads (enchères) | 1643326773739866623 |
Leadbolt | 2899150749497968595 |
LG U+AD | 18298738678491729107 |
LINE Ads Network | 3025503711505004547 |
maio | 7505118203095108657 |
maio (enchères) | 1343336733822567166 |
Media.net (enchères) | 2127936450554446159 |
Auto-promotions par médiation | 6060308706800320801 |
Meta Audience Network* * Avant le 6 juin 2022, ce réseau s'appelait "Facebook Audience Network". | 10568273599589928883 |
Meta Audience Network (enchères)* * Avant le 6 juin 2022, ce réseau s'appelait "Facebook Audience Network (enchères)". | 11198165126854996598 |
Mintegral | 1357746574408896200 |
Mintegral (enchères) | 6250601289653372374 |
MobFox | 8079529624516381459 |
MobFox (enchères) | 3086513548163922365 |
MoPub (obsolète) | 10872986198578383917 |
myTarget | 8450873672465271579 |
Nend | 9383070032774777750 |
Nexxen (enchères)* * Avant le 1er mai 2024, ce réseau était appelé "UnrulyX". | 2831998725945605450 |
ONE par AOL (Millennial Media) | 6101072188699264581 |
ONE par AOL (Nexage) | 3224789793037044399 |
OneTag Exchange (enchères) | 4873891452523427499 |
OpenX (enchères) | 4918705482605678398 |
Pangle | 4069896914521993236 |
Pangle (enchères) | 3525379893916449117 |
PubMatic (enchères) | 3841544486172445473 |
Campagne par réservation | 7068401028668408324 |
RhythmOne (enchères) | 2831998725945605450 |
Rubicon (enchères) | 3993193775968767067 |
Planète SK | 734341340207269415 |
Partage (enchères) | 5247944089976324188 |
Smaato (enchères) | 3362360112145450544 |
Équativ (enchères)* * Avant le 12 janvier 2023, ce réseau était appelé "Smart Adserver". | 5970199210771591442 |
Sonobi (enchères) | 3270984106996027150 |
Tapjoy | 7295217276740746030 |
Tapjoy (enchères) | 4692500501762622178 |
Tencent GDT | 7007906637038700218 |
TripleLift (enchères) | 8332676245392738510 |
Unity Ads | 4970775877303683148 |
Unity Ads (enchères) | 7069338991535737586 |
Verizon Media | 7360851262951344112 |
Verve Group (enchères) | 5013176581647059185 |
Vpon | 1940957084538325905 |
Liftoff Monetize* * Avant le 30 janvier 2023, ce réseau était appelé "Vungle". | 1953547073528090325 |
Liftoff Monetize (enchères)* * Avant le 30 janvier 2023, ce réseau était appelé "Vungle (enchères)". | 4692500501762622185 |
Yieldmo (enchères) | 4193081836471107579 |
YieldOne (enchères) | 3154533971590234104 |
Zucks | 5506531810221735863 |
Récompenser l'utilisateur
Lorsque vous prenez une décision, il est important de trouver un équilibre entre l'expérience utilisateur et la validation des récompenses quand récompenser un utilisateur. Les rappels côté serveur peuvent subir des retards avant atteindre les systèmes externes. Il est donc recommandé d'utiliser le rappel côté client pour récompenser l'utilisateur immédiatement, validation de toutes les récompenses à la réception des rappels côté serveur. Ce offre une bonne expérience utilisateur tout en garantissant la validité récompenses.
Toutefois, dans les applications où la validité des récompenses est essentielle (par exemple, affecte l'économie globale du jeu) et l'attribution des récompenses prend plus de temps n'est pas acceptable, il peut être préférable d'attendre le rappel vérifié côté serveur approche.
Données personnalisées
Les applications qui nécessitent des données supplémentaires dans les rappels de validation côté serveur doivent utiliser
les données personnalisées
des annonces avec récompense. Toute valeur de chaîne définie sur une annonce avec récompense
est transmis au paramètre de requête custom_data
du rappel SSV. Si non
la valeur de données personnalisées est définie, la valeur du paramètre de requête custom_data
ne sera pas
présentes dans le rappel SSV.
L'exemple de code suivant montre comment définir les options de validation côté serveur après la l'annonce avec récompense est chargée.
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 } })
Si vous souhaitez définir une chaîne de récompense personnalisée, vous devez le faire avant de diffuser l'annonce.
Validation manuelle de la SSV avec récompense
Étapes effectuées par la classe RewardedAdsVerifier
pour valider une récompense
La validation côté serveur est décrite ci-dessous. Bien que les extraits de code inclus soient en Java et
utiliser la bibliothèque tierce Tink, vous pouvez implémenter ces étapes
dans la langue de votre choix, à l'aide d'une bibliothèque tierce compatible
ECDSA :
Récupérer des clés publiques
Pour valider un rappel de validation côté serveur avec récompense, vous devez disposer d'une clé publique fournie par AdMob.
Une liste de clés publiques à utiliser pour valider les rappels de SSV avec récompense peut être récupérées à partir de la clé AdMob Google Cloud. La liste des clés publiques est fournie sous forme de représentation JSON dans un format semblable à celui-ci:
{
"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=="
},
],
}
Pour récupérer les clés publiques, connectez-vous au serveur de clés AdMob et téléchargez
clés. Le code suivant permet d'effectuer cette tâche et enregistre le fichier
représentation des clés de la variable 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();
}
Notez que les clés publiques font l'objet d'une rotation régulière. Vous recevrez un e-mail vous en informant d'une prochaine rotation. Si vous mettez en cache des clés publiques, vous devez mettre à jour les clés à la réception de cet e-mail.
Une fois les clés publiques récupérées, elles doivent être analysées. La
La méthode parsePublicKeysJson
ci-dessous accepte une chaîne JSON, comme dans l'exemple
ci-dessus, en entrée, et crée un mappage entre les valeurs key_id
et les clés publiques,
qui sont encapsulés en tant qu'objets ECPublicKey
de la bibliothèque 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;
}
Obtenir le contenu à valider
Les deux derniers paramètres des rappels de SSV avec récompense sont toujours signature
.
et key_id,
dans cet ordre. Les autres paramètres de requête spécifient le contenu
à valider. Supposons que vous ayez configuré AdMob pour envoyer des rappels de récompenses aux
https://www.myserver.com/mypath
L'extrait ci-dessous présente un exemple d'annonce avec récompense
Rappel de validation côté serveur avec le contenu à valider mis en évidence.
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
Le code ci-dessous montre comment analyser le contenu à vérifier à partir d'une URL de rappel en tant que tableau d'octets 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"));
Obtenir la signature et la clé key_id à partir de l'URL de rappel
En utilisant la valeur queryString
de l'étape précédente, analysez signature
et
key_id
à partir de l'URL de rappel, comme indiqué ci-dessous:
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()));
Effectuer la validation
La dernière étape consiste à vérifier le contenu de l'URL de rappel à l'aide de la méthode
la clé publique appropriée. Prenez le mappage renvoyé par
Méthode parsePublicKeysJson
et utiliser le paramètre key_id
du rappel
URL pour obtenir la clé publique à partir de ce mappage. Vérifiez ensuite
la signature avec
de cette clé publique. Ces étapes sont illustrées ci-dessous dans la méthode 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);
}
}
Si la méthode s'exécute sans générer d'exception, l'URL de rappel était validé.
Questions fréquentes
- Puis-je mettre en cache la clé publique fournie par le serveur de clés AdMob ?
- Nous vous recommandons de mettre en cache la clé publique fournie par la clé AdMob pour réduire le nombre d'opérations requises pour valider la validation SSV. . Notez toutefois que les clés publiques font régulièrement l'objet d'une rotation et ne doivent pas être mis en cache pendant plus de 24 heures.
- À quelle fréquence les clés publiques fournies par le serveur de clés AdMob sont-elles alternées ?
- Les clés publiques fournies par le serveur de clés AdMob sont alternées selon une variable programmation. Pour garantir que la vérification des rappels SSV continue de fonctionner les clés publiques ne doivent pas être mises en cache pendant plus de 24 heures.
- Que se passe-t-il si mon serveur n'est pas accessible ?
- Google attend un code de réponse d'état de réussite de
HTTP 200 OK
pour la validation côté serveur. . Si votre serveur n'est pas accessible ou ne fournit pas l'adresse IP attendue Google tentera de nouveau d'envoyer jusqu'à cinq rappels de validation côté serveur des intervalles d'une seconde. - Comment vérifier que les rappels SSV proviennent bien de Google ?
- Utilisez la résolution DNS inverse pour vérifier que les rappels SSV proviennent de Google.