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
- Habilitar en tu bloque de anuncios el sistema de verificación en el servidor para anuncios bonificados.
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
customData.
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
userId.
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 AdMob | 5450213213286189855 |
| Cascada de la red de AdMob | 1215381445328257950 |
| AppLovin | 1063618907739174004 |
| AppLovin (puja) | 1328079684332308356 |
| Bidease (puja) | 3670825090829827805 |
| BidMachine (puja) | 7943972370566394673 |
| Chartboost | 2873236629771172317 |
| Chocolate Platform (puja) | 6432849193975106527 |
| Evento personalizado | 18351550913290782395 |
| 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-mobile | 5208827440166355534 |
| Improve Digital (puja) | 159382223051638006 |
| Index Exchange (puja) | 4100650709078789802 |
| InMobi | 7681903010231960328 |
| InMobi (SDK) (puja) | 8468954295581492586 |
| InMobi Exchange (puja) | 5264320421916134407 |
| ironSource Ads | 6925240245545091930 |
| 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 Network | 3025503711505004547 |
| LY Ads Network (pujas) | 2615812619460460513 |
| Magnite DV+ (puja) | 3993193775968767067 |
| maio | 7505118203095108657 |
| Media.net (puja) | 2127936450554446159 |
| Anuncios internos con mediación | 6060308706800320801 |
| 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 |
| Mintegral | 1357746574408896200 |
| Mintegral (puja) | 6250601289653372374 |
| Mobfox (puja) | 3086513548163922365 |
| MobileFuse (puja) | 7303547408604090310 |
| SDK de Moloco Ads (puja) | 8267622065755668722 |
| myTarget | 8450873672465271579 |
| 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 |
| Pangle | 4069896914521993236 |
| 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 OpenWrap | 7702975372504485373 |
| SDK de PubMatic OpenWrap (puja) | 1234567890123456789 |
| Campaña por reserva | 7068401028668408324 |
| Rise (puja) | 6816468518946650043 |
| Sharethrough (puja) | 5247944089976324188 |
| Smaato (puja) | 3362360112145450544 |
| Sonobi (puja) | 3270984106996027150 |
| TripleLift (puja) | 8332676245392738510 |
| Unity Ads | 4970775877303683148 |
| Unity Ads (puja) | 7069338991535737586 |
| Verve Group (puja) | 5013176581647059185 |
| Vpon | 1940957084538325905 |
| Yieldmo (puja) | 4193081836471107579 |
| YieldOne (puja) | 3154533971590234104 |
| Zucks | 5506531810221735863 |
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:
Sustituye SAMPLE_CUSTOM_DATA_STRING por tus datos personalizados.
Si quieres configurar la cadena de anuncios bonificados personalizados, debes hacerlo antes de mostrar el anuncio.
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 ×tamp=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.