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, qui sont envoyés par Google à un système externe pour l'informer qu'un utilisateur doit être récompensé s'il interagit avec une annonce interstitielle avec récompense ou récompense. Les rappels de validation côté serveur (SSV) avec récompense offrent un niveau de protection supplémentaire contre le spoofing de rappels côté client afin de récompenser les utilisateurs.
Ce guide vous explique comment vérifier les rappels de SSV avec récompense à l'aide de la bibliothèque de chiffrement tierce des applications Java Tink pour vous assurer 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é d'utiliser n'importe quelle bibliothèque tierce compatible avec ECDSA. Vous pouvez également tester votre serveur avec l'outil de test de l'interface utilisateur AdMob.
Consultez cet exemple entièrement fonctionnel en utilisant Java Spring-boot.
Conditions préalables
Intégrez les annonces avec récompense dans votre application mobile via le SDK Google Mobile Ads (version 11.6.0 ou ultérieure) Version 3.12.0 ou ultérieure du plug-in Google Mobile Ads Unity.
Activez la validation côté serveur avec récompense dans votre bloc d'annonces.
Utiliser RécompenseAdsVerifier depuis la bibliothèque d'applications Java de Tink
Le dépôt GitHub des applications Java Tink inclut une classe d'aide RewardedAdsVerifier
permettant de réduire le code requis pour vérifier un rappel de validation côté serveur avec récompense.
Cette classe vous permet de valider une URL de rappel avec le 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, l'URL de rappel a bien été validée. La section Récompenser l'utilisateur détaille les bonnes pratiques concernant les cas où les utilisateurs doivent être récompensés. Pour en savoir plus sur les étapes effectuées par cette classe pour vérifier les rappels de validation côté serveur avec récompense, consultez la section Vérification manuelle des validations SSV avec récompense.
Paramètres de rappel SSV
Les rappels de validation côté serveur contiennent des paramètres de requête qui décrivent l'interaction avec l'annonce avec récompense. Les noms des paramètres, leur description et des exemples de valeurs sont indiqués 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 ayant diffusé cette annonce. Les noms de sources d'annonces correspondant aux valeurs d'ID sont indiqués dans la section Identifiants de sources d'annonces. | 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
.
Si aucune chaîne de données personnalisée n'est fournie par l'application, cette valeur de paramètre de requête ne sera pas présente dans le rappel SSV. |
SAMPLE_CUSTOM_DATA_STRING |
key_id | Clé à utiliser pour vérifier le rappel SSV. Cette valeur correspond à une clé publique fournie par le serveur de clés AdMob. | 1234567890 |
reward_amount | Montant de la récompense indiqué 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 du rappel de la validation côté serveur généré par AdMob. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
timestamp | Horodatage en millisecondes du moment où l'utilisateur a reçu la récompense. | 1507770365237823 |
transaction_id | Identifiant unique encodé en hexadécimal pour chaque événement d'octroi 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 sera pas présent 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 |
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 |
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 (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 décidez de récompenser un utilisateur, il est important de trouver le bon équilibre entre l'expérience utilisateur et la validation des récompenses. Les rappels côté serveur peuvent subir des retards avant d'atteindre les systèmes externes. Par conséquent, il est recommandé d'utiliser le rappel côté client pour récompenser l'utilisateur immédiatement, tout en effectuant la validation de toutes les récompenses à la réception des rappels côté serveur. Cette approche offre une bonne expérience utilisateur tout en garantissant la validité des récompenses accordées.
Toutefois, pour les applications où la validité de la récompense est essentielle (par exemple, si la récompense affecte l'économie de votre application) et que les retards d'attribution des récompenses sont acceptables, l'attente du rappel vérifié côté serveur peut être la meilleure 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 la fonctionnalité de données personnalisées des annonces avec récompense. Toute valeur de chaîne définie sur un objet d'annonce avec récompense est transmise au paramètre de requête custom_data
du rappel SSV. Si aucune valeur de données personnalisée n'est définie, la valeur du paramètre de requête custom_data
ne sera pas présente dans le rappel SSV.
L'exemple de code suivant montre comment définir les options de validation côté serveur une fois l'annonce avec récompense chargée.
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); }
Si vous souhaitez définir la chaîne de récompense personnalisée, vous devez le faire avant de diffuser l'annonce.
Vérification manuelle de la validation des abonnements papier avec récompense
Les étapes effectuées par la classe RewardedAdsVerifier
pour valider une validation SSV avec récompense sont décrites ci-dessous. Bien que les extraits de code inclus soient en Java et exploitent la bibliothèque tierce Tink, vous pouvez mettre en œuvre ces étapes dans le langage de votre choix, à l'aide de n'importe quelle bibliothèque tierce compatible avec ECDSA.
Extraire les clés publiques
Pour valider un rappel de validation côté serveur avec récompense, vous avez besoin 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 extraite du serveur de clés AdMob. La liste des clés publiques est fournie sous la forme d'une 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-les. Le code suivant permet d'effectuer cette tâche et enregistre la représentation JSON des clés dans 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 sont régulièrement alternées. Vous recevrez un e-mail pour vous informer d'une rotation à venir. Si vous mettez en cache des clés publiques, vous devez les mettre à jour à la réception de cet e-mail.
Une fois les clés publiques extraites, elles doivent être analysées. La méthode parsePublicKeysJson
ci-dessous utilise en entrée une chaîne JSON, comme dans l'exemple ci-dessus, et crée un mappage entre les valeurs key_id
et les clés publiques, qui sont encapsulées en tant qu'objets ECPublicKey
à partir 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;
}
Demander la validation d'un contenu
Les deux derniers paramètres de requête des rappels de SSV avec récompense sont toujours signature
et key_id,
, dans cet ordre. Les paramètres de requête restants spécifient le contenu à vérifier. Supposons que vous avez configuré AdMob pour envoyer des rappels de récompenses à https://www.myserver.com/mypath
. L'extrait ci-dessous présente un exemple de rappel SSV avec récompense, avec le contenu à vérifier mis en surbrillance.
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 une signature et un key_id à partir de l'URL de rappel
À l'aide de la valeur queryString
de l'étape précédente, analysez les paramètres de requête 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 avec la clé publique appropriée. Prenez le mappage renvoyé par la méthode parsePublicKeysJson
et utilisez le paramètre key_id
de l'URL de rappel pour obtenir la clé publique à partir de ce mappage. Vérifiez ensuite la signature
avec 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 a bien été validée.
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 le serveur de clés AdMob afin de réduire le nombre d'opérations requises pour valider les rappels SSV. Toutefois, notez que les clés publiques sont régulièrement alternées et ne doivent pas être mises 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 un calendrier variable. Pour que la vérification des rappels SSV continue de fonctionner comme prévu, les clés publiques ne doivent pas être mises en cache pendant plus de 24 heures.
- Que se passe-t-il si mon serveur est inaccessible ?
- Google s'attend à un code de réponse d'état de réussite
HTTP 200 OK
pour les rappels SSV. Si votre serveur n'est pas accessible ou ne fournit pas la réponse attendue, Google réessaie d'envoyer des rappels de SSV jusqu'à cinq fois en intervalles d'une seconde. - Comment vérifier que les rappels SSV proviennent de Google ?
- Utilisez la résolution DNS inverse pour vérifier que les rappels de SSV proviennent de Google.