Las devoluciones de llamada de verificación del servidor son solicitudes de URL con parámetros de consulta que Google expande, que Google envía a un sistema externo para notificarle que un usuario debe recibir un premio por interactuar con un anuncio anuncio intersticial recompensado. Devoluciones de llamada de SSV (verificación del servidor) recompensadas proporcionan una capa adicional de protección contra la falsificación de identidad de devoluciones de llamada del cliente. para recompensar a los usuarios.
En esta guía, se muestra cómo verificar las devoluciones de llamada de SSV recompensadas mediante el uso de Tink Java Apps de terceros criptográfica para garantizar que se apliquen valores legítimos. Si bien Tink se usa para los fines de esta guía, tienes la opción de usar cualquier biblioteca de terceros que admita ECDSA. También puedes probar tu servidor con el módulo de prueba tool en la IU de AdMob.
Mira este video totalmente funcional ejemplo con spring-boot de Java.
Requisitos previos
Integra los anuncios recompensados a tu app para dispositivos móviles con versión 7.28.0 o posterior del SDK de anuncios de Google para dispositivos móviles
Habilitar los anuncios recompensados del servidor verificación en tu unidad de anuncios.
Cómo usar RewardAdsVerifier de la biblioteca de apps de Tink Java
El repositorio de GitHub de Tink Java Apps
incluye un
RewardedAdsVerifier
para reducir el código necesario para verificar una devolución de llamada de SSV recompensada.
Si utilizas esta clase, podrás verificar una URL de devolución de llamada con el siguiente código.
RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
.fetchVerifyingPublicKeysWith(
RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
.build();
String rewardUrl = ...;
verifier.verify(rewardUrl);
Si el método verify()
se ejecuta sin generar una excepción, la devolución de llamada
La URL se verificó correctamente. La columna Recompensar al usuario
se detallan las prácticas recomendadas sobre cuándo se debe recompensar a los usuarios. Para un
desglose de los pasos que realiza esta clase para verificar las devoluciones de llamada de SSV recompensadas
puedes leer el artículo Verificación manual de los
SSV.
Parámetros de devolución de llamada de SSV
Las devoluciones de llamada de verificación del servidor contienen parámetros de consulta que describen el interacción con anuncios recompensados. Los nombres de parámetros, las descripciones y los valores de ejemplo son que se enumeran a continuación. Los parámetros se envían en orden alfabético.
Nombre del parámetro | Descripción | Valor de ejemplo |
---|---|---|
ad_network | Es el identificador de la fuente del anuncio que publicó este anuncio. Fuente del anuncio los nombres correspondientes a los valores de ID se enumeran en la sección Identificadores de origen. | 1953547073528090325 |
ad_unit | Es el ID de unidad de anuncios de AdMob que se usó para solicitar el anuncio recompensado. | 2747237135 |
custom_data | Cadena de datos personalizados proporcionada por
customRewardString
:
Si la aplicación no proporciona ninguna cadena de datos personalizados, este parámetro de consulta no estará presente en la devolución de llamada de SSV. |
SAMPLE_CUSTOM_DATA_STRING |
key_id | Clave que se usará para verificar la devolución de llamada de SSV. Este valor se asigna a una clave pública que proporciona el servidor de claves de AdMob. | 1234567890 |
reward_amount | Es el importe de la recompensa según se especifica en la configuración de la unidad de anuncios. | 5 |
reward_item | Es el elemento de recompensa según se especifica en la configuración de la unidad de anuncios. | monedas |
firma | Firma para la devolución de llamada de SSV generada por AdMob. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
timestamp | Marca de tiempo del momento en que el usuario recibió la recompensa como tiempo de ciclo en ms. | 1507770365237823 |
transaction_id | Es el identificador hexadecimal único con codificación hexadecimal para cada evento de otorgamiento de recompensa generado por AdMob. | 18fa792de1bca816048293fc71035638 |
user_id | Es el identificador de usuario proporcionado por
userIdentifier
Si la app no proporciona un identificador de usuario, este parámetro de búsqueda no estará presente en la devolución de llamada de SSV. |
1234567 |
Identificadores de la fuente del anuncio
IDs y nombres de las fuentes del anuncio
Ad source name | Ad source ID |
---|---|
Aarki (bidding) | 5240798063227064260 |
Ad Generation (bidding) | 1477265452970951479 |
AdColony | 15586990674969969776 |
AdColony (non-SDK) (bidding) | 4600416542059544716 |
AdColony (bidding) | 6895345910719072481 |
AdFalcon | 3528208921554210682 |
AdMob Network | 5450213213286189855 |
AdMob Network Waterfall | 1215381445328257950 |
ADResult | 10593873382626181482 |
AMoAd | 17253994435944008978 |
Applovin | 1063618907739174004 |
Applovin (bidding) | 1328079684332308356 |
Chartboost | 2873236629771172317 |
Chocolate Platform (bidding) | 6432849193975106527 |
CrossChannel (MdotM) | 9372067028804390441 |
Custom Event | 18351550913290782395 |
DT Exchange* * Prior to September 21, 2022, this network was called "Fyber Marketplace". | 2179455223494392917 |
EMX (bidding) | 8497809869790333482 |
Fluct (bidding) | 8419777862490735710 |
Flurry | 3376427960656545613 |
Fyber* * This ad source is used for historical reporting. | 4839637394546996422 |
i-mobile | 5208827440166355534 |
Improve Digital (bidding) | 159382223051638006 |
Index Exchange (bidding) | 4100650709078789802 |
InMobi | 7681903010231960328 |
InMobi (bidding) | 6325663098072678541 |
InMobi Exchange (bidding) | 5264320421916134407 |
IronSource | 6925240245545091930 |
ironSource Ads (bidding) | 1643326773739866623 |
Leadbolt | 2899150749497968595 |
LG U+AD | 18298738678491729107 |
LINE Ads Network | 3025503711505004547 |
maio | 7505118203095108657 |
maio (bidding) | 1343336733822567166 |
Media.net (bidding) | 2127936450554446159 |
Mediated house ads | 6060308706800320801 |
Meta Audience Network* * Prior to June 6, 2022, this network was called "Facebook Audience Network". | 10568273599589928883 |
Meta Audience Network (bidding)* * Prior to June 6, 2022, this network was called "Facebook Audience Network (bidding)". | 11198165126854996598 |
Mintegral | 1357746574408896200 |
Mintegral (bidding) | 6250601289653372374 |
MobFox | 8079529624516381459 |
MobFox (bidding) | 3086513548163922365 |
MoPub (deprecated) | 10872986198578383917 |
myTarget | 8450873672465271579 |
Nend | 9383070032774777750 |
Nexxen (bidding)* * Prior to May 1, 2024, this network was called "UnrulyX". | 2831998725945605450 |
ONE by AOL (Millennial Media) | 6101072188699264581 |
ONE by AOL (Nexage) | 3224789793037044399 |
OneTag Exchange (bidding) | 4873891452523427499 |
OpenX (bidding) | 4918705482605678398 |
Pangle | 4069896914521993236 |
Pangle (bidding) | 3525379893916449117 |
PubMatic (bidding) | 3841544486172445473 |
Reservation campaign | 7068401028668408324 |
RhythmOne (bidding) | 2831998725945605450 |
Rubicon (bidding) | 3993193775968767067 |
SK planet | 734341340207269415 |
Sharethrough (bidding) | 5247944089976324188 |
Smaato (bidding) | 3362360112145450544 |
Equativ (bidding)* * Prior to January 12, 2023, this network was called "Smart Adserver". | 5970199210771591442 |
Sonobi (bidding) | 3270984106996027150 |
Tapjoy | 7295217276740746030 |
Tapjoy (bidding) | 4692500501762622178 |
Tencent GDT | 7007906637038700218 |
TripleLift (bidding) | 8332676245392738510 |
Unity Ads | 4970775877303683148 |
Unity Ads (bidding) | 7069338991535737586 |
Verizon Media | 7360851262951344112 |
Verve Group (bidding) | 5013176581647059185 |
Vpon | 1940957084538325905 |
Liftoff Monetize* * Prior to January 30, 2023, this network was called "Vungle". | 1953547073528090325 |
Liftoff Monetize (bidding)* * Prior to January 30, 2023, this network was called "Vungle (bidding)". | 4692500501762622185 |
Yieldmo (bidding) | 4193081836471107579 |
YieldOne (bidding) | 3154533971590234104 |
Zucks | 5506531810221735863 |
Recompensar al usuario
Es importante equilibrar la experiencia del usuario y la validación de recompensas a la hora de tomar decisiones cuándo recompensar a un usuario. Es posible que las devoluciones de llamada del servidor experimenten demoras llegan a los sistemas externos. Por lo tanto, la práctica recomendada es usar la devolución de llamada del cliente para recompensar al usuario de inmediato, mientras realiza la validación de todas las recompensas una vez recibidas las devoluciones de llamada del servidor. Esta proporciona una buena experiencia del usuario, a la vez que garantiza la validez de los permisos recompensas.
Sin embargo, para las aplicaciones en las que la validez de la recompensa es fundamental (por ejemplo, el la recompensa afecta la economía del juego) y los retrasos en el otorgamiento de recompensas aceptable; lo mejor es esperar la devolución de llamada verificada del servidor. enfoque.
Datos personalizados
Las aplicaciones que requieren datos adicionales en las devoluciones de llamada de verificación del servidor deben usar
la función de datos personalizados
de los anuncios recompensados. Cualquier valor de cadena establecido en un anuncio recompensado
el objeto se pasa al parámetro de consulta custom_data
de la devolución de llamada de SSV. Si la respuesta es no
se configura un valor de datos personalizado, el valor del parámetro de consulta custom_data
no será
presente en la devolución de llamada de SSV.
El siguiente ejemplo de código demuestra cómo configurar las opciones de SSV después de la se cargó el anuncio recompensado.
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; }];
Verificación manual de la SSV recompensada
Los pasos que realiza la clase RewardedAdsVerifier
para verificar un anuncio recompensado.
SSV se describen a continuación. Aunque los fragmentos de código incluidos están en Java y
aprovechar la biblioteca de terceros de Tink, puedes implementar estos pasos en
en el idioma que prefieras y en una biblioteca de terceros que admita
ECDSA.
Recupera claves públicas
Para verificar una devolución de llamada de SSV recompensada, debes tener una clave pública proporcionada por AdMob.
Se puede crear una lista de claves públicas que se usarán para validar las devoluciones de llamada de SSV recompensadas. se recuperan de la clave de AdMob servidor. La lista de claves públicas se proporciona como una representación JSON con un formato similar al siguiente:
{
"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=="
},
],
}
Para recuperar las claves públicas, conéctate al servidor de claves de AdMob y descarga la
claves. El siguiente código realiza esta tarea y guarda el archivo JSON
representación de las claves 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();
}
Ten en cuenta que las claves públicas se rotan con regularidad. Recibirás un correo electrónico para informarte de una próxima rotación. Si almacenas en caché claves públicas, debes actualizar las claves cuando reciba este correo electrónico.
Una vez que se recuperaron las claves públicas, se deben analizar. El
El método parsePublicKeysJson
que aparece a continuación toma una cadena JSON, como la del ejemplo.
arriba, como entrada, y crea una asignación de valores key_id
a claves públicas,
que se encapsulan como objetos ECPublicKey
de la biblioteca 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;
}
Cómo solicitar la verificación del contenido
Los últimos dos parámetros de consulta de las devoluciones de llamada de SSV recompensadas siempre son signature
.
y key_id,
en ese orden. Los parámetros de consulta restantes especifican el contenido
que se debe verificar. Supongamos que configuraste AdMob para que envíe devoluciones de llamada de recompensa a
https://www.myserver.com/mypath
En el siguiente fragmento, se muestra un ejemplo de anuncios recompensados
Es la devolución de llamada de SSV con el contenido que se verificará destacado.
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
El siguiente código demuestra cómo analizar el contenido que se verificará a partir de un URL de devolución de llamada como un array de bytes 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"));
Cómo obtener la firma y el key_id de una URL de devolución de llamada
Con el valor queryString
del paso anterior, analiza signature
y
Parámetros de consulta key_id
de la URL de devolución de llamada, como se muestra a continuación:
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()));
Realiza la verificación
El paso final es verificar el contenido de la URL de devolución de llamada con el
la clave pública correspondiente. Toma la asignación que se devuelve del
parsePublicKeysJson
y usa el parámetro key_id
de la devolución de llamada
URL para obtener la clave pública de esa asignación. Luego, verifica la firma con
esa clave pública. Estos pasos se demuestran a continuación en el método 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 el método se ejecuta sin arrojar una excepción, la URL de devolución de llamada se verificó correctamente.
Preguntas frecuentes
- ¿Puedo almacenar en caché la clave pública proporcionada por el servidor de claves de AdMob?
- Te recomendamos que almacenes en caché la clave pública proporcionada por la clave de AdMob reducir el número de operaciones necesarias para validar la SSV devoluciones de llamada. Sin embargo, ten en cuenta que las claves públicas se rotan con regularidad y no deben almacenarse en caché por más de 24 horas.
- ¿Con qué frecuencia se rotan las claves públicas que proporciona el servidor de claves de AdMob?
- Las claves públicas que proporciona el servidor de claves de AdMob se rotan en una variable de un proyecto. Para garantizar que la verificación de las devoluciones de llamada de SSV siga funcionando como las claves públicas no deberían almacenarse en caché por más de 24 horas.
- ¿Qué sucede si no se puede establecer la conexión con mi servidor?
- Google espera un código de respuesta de estado de éxito
HTTP 200 OK
para SSV devoluciones de llamada. Si no se puede acceder al servidor o no proporciona la calidad Google intentará enviar devoluciones de llamada de SSV hasta cinco veces intervalos de un segundo. - ¿Cómo puedo verificar que las devoluciones de llamada de SSV provienen de Google?
- Usa la búsqueda de DNS inversa para verificar que las devoluciones de llamada de SSV se originen en Google.