Quando o criativo vence um leilão, o Google pode informar qual foi o preço
vencedor, caso o snippet HTML ou o URL VAST que define o criativo inclua
a macro
WINNING_PRICE
. O Google retorna o preço vencedor em formato criptografado. Os tópicos a seguir explicam como seu aplicativo pode descriptografar as informações do preço vencedor.
A macro WINNING_PRICE
pode ser incluída em um criativo, por exemplo, com uma solicitação de pixel invisível
renderizada como parte do anúncio:
<div> <script language='JavaScript1.1' src='https://example.com?creativeID=5837243'/> <img src='https://example.com/t.gif?price=%%WINNING_PRICE%%' width='1' height='1'/> </div>
A macro WINNING_PRICE
também pode ser incluída no URL VAST de um criativo de vídeo, mas não no URL de impressão no VAST:
https://example.com/vast/v?price=%%WINNING_PRICE%%
Cenário
- Seu aplicativo inclui a macro
WINNING_PRICE
no snippet HTML ou URL VAST que ele retorna ao Google. - O Google substitui o preço vencedor pela macro na codificação Base64 segura para a Web sem preenchimento (RFC 3548).
- O snippet passa a confirmação no formato escolhido. Por exemplo, a confirmação pode ser transmitida no URL de uma solicitação de pixel invisível renderizada como parte do anúncio.
- No servidor, a base64 segura para a Web decodifica as informações do preço vencedor e descriptografa o resultado.
Dependências
Você precisará de uma biblioteca de criptografia compatível com SHA-1 HMAC, como Openssl.
Exemplo de código
O código de exemplo é fornecido em Java e C++ e pode ser transferido por download do projeto privatedatacommunicationprotocol.
O código de exemplo em Java usa o decodificador base64 do projeto Apache commons. Não será necessário fazer o download do código do Apache commons, porque a implementação de referência inclui a parte necessária e, portanto, é independente.
O exemplo de código C++ usa o método OpenSSL base64 de BIO (link em inglês). Ele usa uma string codificada em base64 segura para a Web (RFC 3548) e a decodifica. Normalmente, strings base64 seguras para a Web substituem o preenchimento "=" por "." (as aspas são adicionadas para maior clareza da leitura e não estão incluídas no protocolo), mas a substituição da macro não preenche o preço criptografado. A implementação de referência adiciona padding porque o OpenSSL tem problemas com strings sem preenchimento.
Codificação
Para ganhar um preço, a criptografia e a descriptografia exigem duas chaves secretas, mas
compartilhadas. Uma chave de integridade e uma chave de criptografia, chamadas de i_key
e e_key
, respectivamente. As duas chaves são fornecidas na configuração da conta como strings base64 seguras para a Web e podem ser encontradas na página do Authorized Buyers em Configurações do bidder > Configurações do RTB > Chaves de criptografia.
Exemplos de chaves de integridade e criptografia:
skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o= // Encryption key (e_key) arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo= // Integrity key (i_key)
As chaves precisam ser decodificadas com segurança para a Web e, em seguida, decodificadas em base64 pelo aplicativo:
e_key = WebSafeBase64Decode('skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=') i_key = WebSafeBase64Decode('arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=')
Esquema de criptografia
O preço é criptografado usando um esquema de criptografia personalizado projetado para minimizar a sobrecarga de tamanho e garantir a segurança adequada. O esquema de criptografia usa um algoritmo HMAC com chave para gerar um bloco de chave secreta com base no ID do evento de impressão exclusivo.
O preço criptografado tem um comprimento fixo de 28 bytes. Ele é composto por um vetor de inicialização de 16 bytes, 8 bytes de texto criptografado e uma assinatura de integridade de 4 bytes. O preço criptografado é codificado em base64 seguro para a Web, de acordo com o RFC 3548, com caracteres de preenchimento omitidos. Assim, o preço criptografado de 28 bytes é codificado como uma string base-64 segura para a Web de 38 caracteres, independentemente do preço vencedor pago.
Exemplos de preços criptografados:
YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCce_6msaw // 100 CPI micros YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCAWJRxOgA // 1900 CPI micros YWJjMTIzZGVmNDU2Z2hpN7fhCuPemC32prpWWw // 2700 CPI micros
O formato criptografado é:
{initialization_vector (16 bytes)}{encrypted_price (8 bytes)} {integrity (4 bytes)}
O preço é criptografado como <price xor HMAC(encryption_key,
initialization_vector)>
. Portanto, a descriptografia calcula
HMAC(encryption_key,initialization_vector)
e xor com o
preço criptografado para reverter a criptografia. O estágio de integridade usa 4 bytes de
<HMAC(integrity_key, price||initialization_vector)>
, em que
||
é concatenação.
Entradas | |
---|---|
iv |
vetor de inicialização (16 bytes - exclusivo da impressão) |
e_key |
chave de criptografia (32 bytes - fornecida durante a configuração da conta) |
i_key |
chave de integridade (32 bytes - fornecida durante a configuração da conta) |
price |
(8 bytes - em micros da moeda da conta) |
Notation | |
hmac(k, d) |
HMAC SHA-1 de dados d , usando a chave k |
a || b |
string a concatenada com a string b |
Pseudocódigo | |
pad = hmac(e_key, iv) // first 8 bytes enc_price = pad <xor> price signature = hmac(i_key, price || iv) // first 4 bytes final_message = WebSafeBase64Encode( iv || enc_price || signature ) |
Esquema de descriptografia
Seu código de descriptografia precisa descriptografar o preço usando a chave de criptografia e verificar os bits de integridade com ela. As chaves serão fornecidas a você durante a configuração. Não há restrições nos detalhes de como você estrutura a implementação. Na maioria das vezes, você deve ser capaz de pegar o exemplo de código e adaptá-lo de acordo com suas necessidades.
Entradas | |
---|---|
e_key |
Chave de criptografia de 32 bytes - fornecida durante a configuração da conta |
i_key |
Chave de integridade, 32 bytes - fornecida durante a configuração da conta |
final_message |
Codificação em base64 segura para a Web de 38 caracteres |
Pseudocódigo | |
// Base64 padding characters are omitted. // Add any required base64 padding (= or ==). final_message_valid_base64 = AddBase64Padding(final_message) // Web-safe decode, then base64 decode. enc_price = WebSafeBase64Decode(final_message_valid_base64) // Message is decoded but remains encrypted. (iv, p, sig) = enc_price // Split up according to fixed lengths. price_pad = hmac(e_key, iv) price = p <xor> price_pad conf_sig = hmac(i_key, price || iv) success = (conf_sig == sig) |
Detecte ataques de resposta desatualizada
Para detectar ataques de repetição ou resposta desatualizada, é recomendável filtrar as respostas com um carimbo de data/hora que seja diferente do horário do sistema, depois de considerar as diferenças de fuso horário.
O vetor de inicialização contém um carimbo de data/hora nos primeiros 8 bytes. Ele pode ser lido pela seguinte função C++:
void GetTime(const char* iv, struct timeval* tv) { uint32 val; memcpy(&val, iv, sizeof(val)); tv->tv_sec = htonl(val); memcpy(&val, iv+sizeof(val), sizeof(val)); tv->tv_usec = htonl(val) }
O carimbo de data/hora pode ser convertido em um formato legível usando o seguinte código C++:
struct tm tm; localtime_r(&tv->tv_sec, &tm); printf("%04d-%02d-%02d|%02d:%02d:%02d.%06ld", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tv_.tv_usec);
Biblioteca Java
Em vez de implementar os algoritmos criptográficos para codificar e decodificar o preço vencedor, é possível usar o DoubleClickCrypto.java. Para mais informações, consulte Criptografia.