Decriptazione dei prezzi di conferma

Quando la creatività vince un'asta, Google può comunicarti il prezzo vincente se lo snippet HTML o l'URL VAST che definisce la creatività include la macro WINNING_PRICE. Google restituisce il prezzo vincente in formato criptato. I seguenti argomenti spiegano in che modo la tua applicazione può decriptare le informazioni sul prezzo vincente.

La macro WINNING_PRICE può essere inclusa in una creatività, ad esempio con una richiesta di pixel invisibile visualizzata all'interno dell'annuncio:

<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>

La macro WINNING_PRICE può essere inclusa anche nell'URL VAST di una creatività video (ma non nell'URL delle impressioni in VAST):

https://example.com/vast/v?price=%%WINNING_PRICE%%

Scenario

  1. La tua applicazione include la macro WINNING_PRICE nello snippet HTML o nell'URL VAST che restituisce a Google.
  2. Google sostituisce il prezzo vincente per la macro con codifica Base64 sicura per il web senza riempimento (RFC 3548).
  3. Lo snippet trasmette la conferma nel formato che hai scelto. Ad esempio, la conferma potrebbe essere passata nell'URL di una richiesta di pixel invisibile visualizzata all'interno dell'annuncio.
  4. Sul server, l'applicazione Base64 sicura per il web decodifica le informazioni sul prezzo vincente e decripta il risultato.

Dipendenze

Avrai bisogno di una libreria di crittografia che supporti l'HMAC SHA-1, come Openssl.

Codice campione

Il codice campione viene fornito in Java e C++ e può essere scaricato dal progetto privatedatacommunicationprotocollo.

  • Il codice di esempio Java utilizza il decoder base64 del progetto Apache Commons. Non sarà necessario scaricare il codice Apache Commons, poiché l'implementazione del riferimento include la parte necessaria ed è quindi indipendente.

  • Il codice campione C++ utilizza il metodo BIO OpenSSL base64. Richiede una stringa codificata in Base64 sicura per il web (RFC 3548) e la decodifica. Normalmente, le stringhe Base64 sicure per il web sostituiscono "=" spaziatura interna con "." (tieni presente che le virgolette vengono aggiunte per chiarezza e non sono incluse nel protocollo), ma la sostituzione macro non limita il prezzo criptato. L'implementazione del riferimento aggiunge spaziatura interna perché OpenSSL ha problemi con le stringhe non riempite.

Codifica

Per ottenere la crittografia e la decrittografia del prezzo vincente, sono necessarie due chiavi secret, ma condivise. Una chiave di integrità e una chiave di crittografia, denominate rispettivamente i_key e e_key. Entrambe le chiavi vengono fornite durante la configurazione dell'account come stringhe Base64 sicure per il web e sono disponibili nella pagina di Authorized Buyers in Impostazioni strumento di offerta > Impostazioni RTB > Chiavi di crittografia.

Esempi di chiavi di integrità e crittografia:

skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=  // Encryption key (e_key)
arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=  // Integrity key (i_key)

Le chiavi devono essere decodificate in sicurezza per il web e poi decodificate in base64 dalla tua applicazione:

e_key = WebSafeBase64Decode('skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=')
i_key = WebSafeBase64Decode('arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=')

Schema di crittografia

Il prezzo viene criptato tramite uno schema di crittografia personalizzato progettato per ridurre al minimo l'overhead delle dimensioni, garantendo al contempo una sicurezza adeguata. Lo schema di crittografia utilizza un algoritmo HMAC con chiave per generare un secret pad basato sull'ID evento di impressione univoco.

Il prezzo criptato ha una lunghezza fissa di 28 byte. È composto da un vettore di inizializzazione di 16 byte, 8 byte di testo crittografato e una firma di integrità a 4 byte. Il prezzo criptato è sicuro per il web con codifica Base64, secondo RFC 3548, con i caratteri di spaziatura interna omessi. Pertanto, il prezzo criptato a 28 byte viene codificato come stringa Base64 sicura per il web di 38 caratteri, a prescindere dal prezzo vincente pagato.

Esempi di prezzi criptati:

YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCce_6msaw  // 100 CPI micros
YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCAWJRxOgA  // 1900 CPI micros
YWJjMTIzZGVmNDU2Z2hpN7fhCuPemC32prpWWw  // 2700 CPI micros

Il formato criptato è:

{initialization_vector (16 bytes)}{encrypted_price (8 bytes)}
{integrity (4 bytes)}

Il prezzo è criptato come <price xor HMAC(encryption_key, initialization_vector)>, quindi la decrittografia calcola HMAC(encryption_key,initialization_vector) e xor con il prezzo criptato per annullare la crittografia. La fase di integrità richiede 4 byte di <HMAC(integrity_key, price||initialization_vector)> dove || è la concatenazione.

nascosti
iv Vettore di inizializzazione (16 byte, univoco per l'impressione)
e_key chiave di crittografia (32 byte, fornita al momento della configurazione dell'account)
i_key chiave di integrità (32 byte, fornita al momento della configurazione dell'account)
price (8 byte, in micro della valuta dell'account)
Notazione
hmac(k, d) HMAC SHA-1 dei dati d, utilizzando la chiave k
a || b stringa a concatenata con la stringa b
Pseudocodice
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 )

Schema di decrittografia

Il codice di decriptazione deve decriptare il prezzo utilizzando la chiave di crittografia e verificare i bit di integrità con la chiave di integrità. Le chiavi ti verranno fornite durante la configurazione. Non sono previste limitazioni ai dettagli della struttura dell'implementazione. Nella maggior parte dei casi, dovresti essere in grado di adattare il codice campione alle tue esigenze.

nascosti
e_key chiave di crittografia, 32 byte, fornita al momento della configurazione dell'account
i_key chiave di integrità, 32 byte, fornita al momento della configurazione dell'account
final_message 38 caratteri sicuri per il web e codificati in Base64
Pseudocodice
// 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)

Rileva attacchi con risposta obsoleta

Per rilevare risposte inattive o attacchi di ripetizione, ti consigliamo di filtrare le risposte con un timestamp che differisce in modo significativo dall'ora del sistema, dopo aver tenuto conto delle differenze di fuso orario.

Il vettore di inizializzazione contiene un timestamp nei primi 8 byte. Può essere letto dalla seguente funzione 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)
}

Il timestamp può essere convertito in un formato leggibile utilizzando il seguente codice 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);

Libreria Java

Anziché implementare gli algoritmi di crittografia per codificare e decodificare il prezzo vincente, puoi utilizzare DoubleClickCrypto.java. Per scoprire di più, consulta la sezione Crittografia.