Os callbacks de verificação do lado do servidor são solicitações de URL com parâmetros de consulta expandido pelo Google, que são enviados pelo Google a um sistema externo para notificá-lo de que um usuário deve ser recompensado por interagir com um anúncio premiado anúncio intersticial premiado. Callbacks de SSV (verificação do lado do servidor) premiados fornecem uma camada extra de proteção contra spoofing de callbacks do lado do cliente. para recompensar os usuários.
Neste guia, mostramos como verificar callbacks de SSV premiados usando o Apps Java do Tink de terceiros para garantir que os parâmetros de consulta no callback sejam valores legítimos. Embora o Tink seja usado para os fins deste guia, você pode usar qualquer biblioteca de terceiros que ofereça suporte ECDSA, em inglês. Você também pode testar seu servidor com o recurso de teste ferramenta na interface da AdMob.
Confira esta ferramenta totalmente exemplo usando o spring-boot do Java.
Pré-requisitos
Integre anúncios premiados às suas aplicativo móvel com v3.12.0 ou mais recente do plug-in dos anúncios para dispositivos móveis do Google para Unity.
Ativar prêmios do lado do servidor verificação no seu bloco de anúncios.
Usar o PremieAdsVerifier da biblioteca do Tink com Java Apps
O repositório Apps Java do Tink no GitHub
inclui um
RewardedAdsVerifier
para reduzir o código necessário para verificar um callback de SSV premiado.
O uso dessa classe permite verificar um URL de callback com o código a seguir.
RewardedAdsVerifier verifier = new RewardedAdsVerifier.Builder()
.fetchVerifyingPublicKeysWith(
RewardedAdsVerifier.KEYS_DOWNLOADER_INSTANCE_PROD)
.build();
String rewardUrl = ...;
verifier.verify(rewardUrl);
Se o método verify()
for executado sem gerar uma exceção, o callback
O URL foi verificado. A seção Recompensar o usuário
a seção detalha as práticas recomendadas sobre quando os usuários devem ser recompensados. Para um
detalhamento das etapas realizadas por esta classe para verificar callbacks de SSV premiados;
confira a Verificação manual de anúncios
SSV.
Parâmetros de callback de SSV
Os callbacks de verificação do lado do servidor contêm parâmetros de consulta que descrevem a interação com anúncios premiados. Os nomes dos parâmetros, as descrições e os valores de exemplo são listadas abaixo. Os parâmetros são enviados em ordem alfabética.
Nome do parâmetro | Descrição | Valor de exemplo |
---|---|---|
ad_network | O identificador da origem de anúncios que forneceu o anúncio em questão. Origem de anúncios nomes correspondentes aos valores de ID são listados no campo identificadores de origem. | 1953547073528090325 |
ad_unit | ID do bloco de anúncios da AdMob usado para solicitar o anúncio premiado. | 2747237135 |
key_id | Chave a ser usada para verificar o callback de SSV. Esse valor mapeia para uma chave pública fornecidos pelo servidor de chaves da AdMob. | 1234567890 |
reward_amount | O valor do prêmio especificado nas configurações do bloco de anúncios. | 5 |
reward_item | Item do prêmio conforme especificado nas configurações do bloco de anúncios. | moedas |
assinatura | Assinatura para retorno de chamada de SSV gerado pela AdMob. | MEUCIQCLJS_s4ia_sN06HqzeW7Wc3nhZi4RlW3qV0oO-6AIYdQIgGJEh-rzKreO-paNDbSCzWGMtmgJHYYW9k2_icM9LFMY |
timestamp | Carimbo de data/hora de quando o usuário foi recompensado como horário do período em ms. | 1507770365237823 |
transaction_id | Identificador exclusivo codificado em hexadecimal para cada evento de concessão de prêmio gerado pela AdMob. | 18fa792de1bca816048293fc71035638 |
user_id | Identificador do usuário conforme fornecido por
SetUserId .
Se nenhum identificador de usuário for fornecido pelo aplicativo, este parâmetro de consulta não no retorno de chamada SSV. |
1234567 |
Identificadores da origem de anúncios
Nomes e IDs das origens de anúncios
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 o usuário
É importante equilibrar a experiência do usuário e a validação da recompensa ao decidir quando recompensar um usuário. Os callbacks do lado do servidor podem apresentar atrasos antes para alcançar sistemas externos. Portanto, a prática recomendada é usar no callback do lado do cliente para recompensar o usuário imediatamente, enquanto realiza validação em todos os prêmios após o recebimento de callbacks do lado do servidor. Isso fornece uma boa experiência do usuário, garantindo a validade recompensas.
No entanto, para aplicativos em que a validade da recompensa é crítica (por exemplo, afeta a economia do jogo) e atrasos na concessão de prêmios são aceitável, aguardar o retorno de chamada verificado do servidor pode ser o melhor abordagem humilde.
Dados personalizados
Apps que exigem dados extras em callbacks de verificação do lado do servidor precisam usar
o recurso de dados personalizados dos anúncios premiados. Qualquer valor de string definido em um anúncio premiado
é transmitido ao parâmetro de consulta custom_data
do callback SSV. Em caso negativo
valor de dados personalizado estiver definido, o valor do parâmetro de consulta custom_data
não será
presentes no retorno de chamada de SSV.
O exemplo de código a seguir demonstra como definir as opções de SSV após o anúncio premiado é carregado.
private void LoadRewardedAd(string adUnitId)
{
// Send the request to load the ad.
AdRequest adRequest = new AdRequest();
RewardedAd.Load(adUnitId, adRequest, (RewardedAd rewardedAd, LoadAdError error) =>
{
// If the operation failed with a reason.
if (error != null)
{
Debug.LogError("Rewarded ad failed to load an ad with error : " + error);
return;
}
var options = new ServerSideVerificationOptions
.Builder()
.SetCustomData("SAMPLE_CUSTOM_DATA_STRING")
.Build()
rewardedAd.SetServerSideVerificationOptions(options);
});
}
Se você quiser definir uma string de prêmio personalizada, faça isso antes de exibir o anúncio.
Verificação manual de SSV concedido como prêmio
As etapas realizadas pela classe RewardedAdsVerifier
para verificar um anúncio premiado
SSV são descritas abaixo. Embora os snippets de código incluídos estejam em Java e
usam a biblioteca de terceiros Tink, essas etapas podem ser implementadas por você
no idioma de sua escolha, usando qualquer biblioteca de terceiros que oferece suporte
ECDSA, em inglês.
Buscar chaves públicas
Para verificar um callback de SSV concedido como prêmio, você precisa de uma chave pública fornecida pela AdMob.
Uma lista de chaves públicas a serem usadas para validar os callbacks de SSV premiados pode ser buscados na chave da AdMob servidor. A lista de chaves públicas é fornecido como uma representação JSON com um formato semelhante ao seguinte:
{
"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 as chaves públicas, conecte-se ao servidor de chaves da AdMob e faça o download do
chaves. O código a seguir realiza essa tarefa e salva o arquivo JSON
representação das chaves para a variável 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();
}
As chaves públicas são alternadas regularmente. Você vai receber um e-mail informando sobre uma rotação futura. Se estiver armazenando chaves públicas em cache, atualize as chaves ao receber o e-mail.
Depois que as chaves públicas forem buscadas, elas precisarão ser analisadas. A
O método parsePublicKeysJson
abaixo usa uma string JSON, como no exemplo
acima, como entrada, e cria um mapeamento de valores key_id
para chaves públicas,
que são encapsulados como objetos ECPublicKey
da biblioteca do 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;
}
Solicitar que o conteúdo seja verificado
Os dois últimos parâmetros de consulta dos callbacks de SSV premiados são sempre signature
.
e key_id,
, nessa ordem. Os outros parâmetros de consulta especificam o conteúdo
a serem verificados. Vamos supor que você tenha configurado a AdMob para enviar callbacks de prêmios a
https://www.myserver.com/mypath
: O snippet abaixo mostra um exemplo de anúncio
Callback de SSV com o conteúdo a ser verificado 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
O código abaixo demonstra como analisar o conteúdo a ser verificado em um URL de callback como uma 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"));
Obter assinatura e key_id do URL de callback
Usando o valor queryString
da etapa anterior, analise o signature
e
Parâmetros de consulta key_id
do URL de callback, conforme mostrado abaixo:
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()));
Fazer a verificação
A etapa final é verificar o conteúdo do URL de callback com o
a chave pública apropriada. Pegue o mapeamento retornado do
parsePublicKeysJson
e use o parâmetro key_id
do callback
URL para obter a chave pública desse mapeamento. Em seguida, verifique a assinatura com
essa chave pública. Essas etapas são demonstradas abaixo no 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);
}
}
Se o método for executado sem gerar uma exceção, o URL de callback foi verificado com sucesso.
Perguntas frequentes
- Posso armazenar em cache a chave pública fornecida pelo servidor de chaves da AdMob?
- Recomendamos que você armazene em cache a chave pública fornecida pela chave da AdMob servidor para reduzir o número de operações necessárias para validar a SSV . No entanto, as chaves públicas são alternadas regularmente e não devem armazenados em cache por mais de 24 horas.
- Com que frequência as chaves públicas fornecidas pelo servidor de chaves da AdMob são alternadas?
- As chaves públicas fornecidas pelo servidor de chaves da AdMob são alternadas em uma variável cronograma. Para garantir que a verificação das chamadas de retorno de SSV continue funcionando pretendido, as chaves públicas não podem ser armazenadas em cache por mais de 24 horas.
- O que acontece se não for possível acessar o servidor?
- O Google espera um código de resposta de status de sucesso
HTTP 200 OK
para SSV . Se o servidor não puder ser acessado ou não fornecer o serviço resposta, o Google tentará enviar callbacks SSV até cinco vezes em em intervalos de um segundo. - Como posso verificar se os callbacks de SSV são provenientes do Google?
- Usar a busca DNS reversa para verificar se os callbacks de SSV são originados do Google.