Verificación del lado del servidor

Las retrollamadas de verificación del lado del servidor (retrollamadas de SSV) son solicitudes de URL con parámetros de consulta mostrados por Google y que Google envía a un sistema externo para notificarle que hay que recompensar a un usuario porque ha interactuado con un anuncio bonificado o un anuncio intersticial bonificado. Las retrollamadas bonificadas de verificación del lado del servidor proporcionan una capa adicional de protección contra el spoofing de retrollamadas del lado del cliente para recompensar a los usuarios.

En esta guía aprenderás a verificar retrollamadas de SSV de anuncios bonificados mediante la biblioteca criptográfica de terceros Tink Java Apps para comprobar la legitimidad de los parámetros de consulta de las retrollamadas. Si bien en esta guía utilizamos Tink, puedes emplear cualquier biblioteca de terceros que sea compatible con ECDSA. También puedes comprobar si tu servidor funciona correctamente con la herramienta de pruebas de la UI de AdMob.

Requisitos previos

Usar RewardedAdsVerifier de la biblioteca Tink Java Apps

El repositorio GitHub de Tink Java Apps incluye la clase auxiliar RewardedAdsVerifier, con la que se reduce la cantidad de código necesario para verificar una retrollamada de SSV de anuncio bonificado. Al usar esta clase, puedes verificar una URL de retrollamada 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 ninguna excepción, la URL de retrollamada se verifica correctamente. En la sección Recompensar a los usuarios puedes consultar las prácticas recomendadas a este respecto. Si prefieres ver un desglose de los pasos que sigue esta clase para verificar las retrollamadas de SSV de anuncios bonificados, consulta la sección Verificación manual de SSVs de anuncios bonificados.

Parámetros de la retrollamada de SSV

Las retrollamadas de verificación del lado del servidor contienen parámetros de consulta que describen la interacción con anuncio bonificado. A continuación se indican los nombres y las descripciones de estos parámetros, así como ejemplos de los valores que utilizan. Todos los parámetros se envían en orden alfabético.

Nombre del parámetro Descripción Valor de ejemplo
ad_network Identificador de la fuente publicitaria que ha mostrado este anuncio. Puedes consultar los nombres de las fuentes publicitarias correspondientes a los valores de ID en la sección Identificadores de fuentes publicitarias. 1953547073528090325
ad_unit ID del bloque de anuncios de AdMob utilizado para solicitar el anuncio bonificado. 2747237135
custom_data Cadena de datos personalizados que proporciona customRewardString.

Si la aplicación no proporciona ninguna cadena de datos personalizados, el valor de este parámetro de consulta no estará presente en la retrollamada de SSV.

EJEMPLO_CADENA_DATOS_PERSONALIZADOS
key_id Clave que se utilizará para verificar la retrollamada de SSV. Este valor se asigna a una clave pública que facilita el servidor de claves de AdMob. 1234567890
reward_amount Importe de la bonificación especificada en la configuración del bloque de anuncios. 5
reward_item Elemento de bonificación, tal como se especifica en la configuración del bloque de anuncios. coins
signature Firma de la retrollamada de SSV generada por AdMob. MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY
timestamp Marca de tiempo Epoch, en milisegundos, que indica cuándo se recompensó al usuario. 1507770365237823
transaction_id Identificador único codificado en hexadecimal para cada evento de concesión de bonificación que genera AdMob. 18fa792de1bca816048293fc71035638
user_id Identificador de usuario proporcionado por userIdentifier.

Si la aplicación no proporciona ningún identificador de usuario, este parámetro de consulta no estará presente en la retrollamada de SSV.

1234567

Identificadores de fuentes publicitarias

Nombres e IDs de fuentes publicitarias

Nombre de la fuente publicitaria ID de la fuente publicitaria
Ad Generation (puja)1477265452970951479
Red de AdMob5450213213286189855
Cascada de la red de AdMob1215381445328257950
AppLovin1063618907739174004
AppLovin (puja)1328079684332308356
Bidease (puja)3670825090829827805
BidMachine (puja)7943972370566394673
Chartboost2873236629771172317
Chocolate Platform (puja)6432849193975106527
Evento personalizado18351550913290782395
DT Exchange*

* Antes del 21 de septiembre del 2022, esta red se llamaba "Fyber Marketplace".

2179455223494392917
DT Exchange (puja)8189833498765234879
Equativ (puja)*

* Antes del 12 de enero del 2023, esta red se llamaba "Smart Adserver".

5970199210771591442
Fluct (puja)8419777862490735710
i-mobile5208827440166355534
Improve Digital (puja)159382223051638006
Index Exchange (puja)4100650709078789802
InMobi7681903010231960328
InMobi (SDK) (puja)8468954295581492586
InMobi Exchange (puja)5264320421916134407
ironSource Ads6925240245545091930
ironSource Ads (pujas)1643326773739866623
Liftoff Monetize*

* Antes del 30 de enero del 2023, esta red se llamaba "Vungle".

1953547073528090325
Liftoff Monetize (puja)*

* Antes del 30 de enero del 2023, esta red se llamaba "Vungle (puja)".

4692500501762622185
LY Ads Network3025503711505004547
LY Ads Network (pujas)2615812619460460513
Magnite DV+ (puja)3993193775968767067
maio7505118203095108657
Media.net (puja)2127936450554446159
Anuncios internos con mediación6060308706800320801
Meta Audience Network*

* Antes del 6 de junio del 2022, esta red se llamaba "Facebook Audience Network".

10568273599589928883
Meta Audience Network (puja)*

* Antes del 6 de junio del 2022, esta red se llamaba "Facebook Audience Network (puja)".

11198165126854996598
Mintegral1357746574408896200
Mintegral (puja)6250601289653372374
Mobfox (puja)3086513548163922365
MobileFuse (puja)7303547408604090310
SDK de Moloco Ads (puja)8267622065755668722
myTarget8450873672465271579
Nativo (puja)3240503836211327896
Nexxen (puja)*

* Antes del 1 de mayo del 2024, esta red se llamaba "UnrulyX".

2831998725945605450
OneTag Exchange (puja)4873891452523427499
OpenX (puja)4918705482605678398
Pangle4069896914521993236
SDK de Pangle (Corea del Sur) (puja)12171279046073404914
SDK de Pangle (resto del mundo) (pujas)3525379893916449117
SDK de Pangle (EE. UU.) (puja)15999446638585856012
PubMatic (puja)3841544486172445473
SDK de PubMatic OpenWrap7702975372504485373
SDK de PubMatic OpenWrap (puja)1234567890123456789
Campaña por reserva7068401028668408324
Rise (puja)6816468518946650043
Sharethrough (puja)5247944089976324188
Smaato (puja)3362360112145450544
Sonobi (puja)3270984106996027150
TripleLift (puja)8332676245392738510
Unity Ads4970775877303683148
Unity Ads (puja)7069338991535737586
Verve Group (puja)5013176581647059185
Vpon1940957084538325905
Yieldmo (puja)4193081836471107579
YieldOne (puja)3154533971590234104
Zucks5506531810221735863

Recompensar a los usuarios

A la hora de decidir cuándo recompensar a los usuarios, es importante equilibrar la experiencia que les ofreces con el proceso de validación de las bonificaciones. Las retrollamadas del servidor pueden tardar en llegar a los sistemas externos; por tanto, lo más recomendable es usar la retrollamada del cliente para recompensar al usuario de inmediato y validar todas las bonificaciones tras recibir una retrollamada del servidor. Esta estrategia mejora la experiencia de los usuarios, al tiempo que se asegura la validez de las bonificaciones concedidas.

Sin embargo, si la validez de la bonificación es importante (por ejemplo, porque afecta a la economía de tu aplicación durante el juego) y es aceptable que se produzcan ciertos retrasos en la concesión de las bonificaciones, puede que la mejor estrategia sea esperar a la retrollamada de SSV.

Datos personalizados

Las aplicaciones que requieren datos adicionales en las retrollamadas de verificación del lado del servidor deben usar la función de datos personalizados de los anuncios bonificados. Los valores de cadena asignados a un objeto de anuncio bonificado se envían al parámetro de consulta custom_data de la retrollamada de SSV. Si no se asigna ningún valor de datos personalizados, el valor del parámetro de consulta custom_data no estará presente en la retrollamada de SSV.

En el siguiente ejemplo se definen las opciones de SSV después de cargar el anuncio bonificado:

Swift

RewardedAd.load(with:"AD_UNIT_ID",
                       request: request,
                       completionHandler: { [self] ad, error in
      if let error != error {
      rewardedAd = ad
      let options = ServerSideVerificationOptions()
      options.customRewardString = "SAMPLE_CUSTOM_DATA_STRING"
      rewardedAd.serverSideVerificationOptions = options
    }
})

Objective‑C

GADRequest *request = [GADRequest request];
[GADRewardedAd loadWithAdUnitID:@"AD_UNIT_ID"
                        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 SSVs de anuncios bonificados

A continuación se describen los pasos que sigue la clase RewardedAdsVerifier para verificar en el servidor un anuncio bonificado. Aunque los fragmentos de código incluidos están en Java y se sirven de la biblioteca de terceros Tink, puedes implementar estos pasos en el lenguaje que prefieras y utilizar cualquier biblioteca de terceros compatible con ECDSA.

Obtener claves públicas

Para verificar una retrollamada de SSV de anuncios bonificados, necesitas una clave pública proporcionada por AdMob.

En el servidor de claves de AdMob hay una lista con las claves públicas que se usan para validar las retrollamadas de SSV de anuncios bonificados. Dicha lista 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 obtener las claves públicas, conéctate al servidor de claves de AdMob y descárgalas. El siguiente código realiza esta tarea y guarda la representación JSON de las claves en 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 rotan periódicamente. Cuando se aproxime una rotación, se te informará por correo electrónico. Si guardas las claves públicas en la caché, cuando recibas dicho mensaje deberás actualizarlas.

Después de obtener las claves públicas, es necesario analizarlas. El método parsePublicKeysJson que aparece a continuación utiliza una cadena JSON como entrada (igual que en el ejemplo anterior), y asigna 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;
}

Obtener el contenido que hay que verificar

Los dos últimos parámetros de consulta de las retrollamadas de SSV de los anuncios bonificados son siempre signature y key_id,, en ese orden. El resto de los parámetros sirven para especificar qué contenido hay que verificar. Supongamos que has configurado AdMob para enviar retrollamadas de anuncios bonificados a https://www.myserver.com/mypath. En el siguiente fragmento de código se muestra un ejemplo de retrollamada de SSV correspondiente a un anuncio bonificado; el contenido que hay que verificar aparece resaltado.

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

En el siguiente código se muestra cómo analizar el contenido que hay que verificar desde una URL de retrollamada, como una matriz 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"));

Obtener la firma y el ID de clave de la URL de retrollamada

Usa el valor queryString del paso anterior para analizar los parámetros de consulta signature y key_id de la URL de retrollamada, tal 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()));

Realizar la verificación

El último paso es verificar el contenido de la URL de retrollamada mediante la clave pública correspondiente. Utiliza el parámetro key_id de la URL de retrollamada para obtener la clave pública a partir de la asignación que haya devuelto el método parsePublicKeysJson. A continuación, verifica la firma con esa clave pública. Estos pasos se muestran 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 generar ninguna excepción, la URL de retrollamada se verifica correctamente.

Preguntas frecuentes

¿Puedo almacenar en caché la clave pública que proporciona el servidor de claves de AdMob?
Te recomendamos que lo hagas, ya que así se necesitarán menos operaciones para validar las retrollamadas de SSV. Sin embargo, ten en cuenta que las claves públicas rotan periódicamente y no deben almacenarse en caché durante más de 24 horas.
¿Con qué frecuencia rotan las claves públicas que proporciona el servidor de claves de AdMob?
Rotan con una programación variable. Para que la verificación de las retrollamadas de SSV siga funcionando correctamente, las claves públicas no deben almacenarse en caché durante más de 24 horas.
¿Qué ocurre si no se puede establecer la conexión con mi servidor?
Google espera obtener de las retrollamadas de SSV un código de respuesta de estado correcto (HTTP 200 OK). Si no se puede establecer la conexión con tu servidor o este no proporciona la respuesta esperada, Google intentará enviar de nuevo las retrollamadas de SSV hasta cinco veces, con intervalos de un segundo.
¿Cómo puedo verificar que las retrollamadas de SSV proceden de Google?
Utiliza la petición de DNS invertida para verificar que provienen de Google.