Quando la tua creatività vince un'asta, Google può informarti del prezzo vincente se la creatività include la macro ${AUCTION_PRICE}
.
Quando la macro viene espansa, restituisce il prezzo vincente in forma criptata. Può essere incluso in una creatività, ad esempio con una richiesta di pixel invisibile visualizzata nell'ambito dell'annuncio:
<div> <script language='JavaScript1.1' src='https://example.com?creativeID=5837243'/> <img src='https://example.com/t.gif?price=${AUCTION_PRICE}' width='1' height='1'/> </div>
La macro ${AUCTION_PRICE}
può essere inclusa anche nell'URL VAST di una creatività video, ma non nell'URL impressione in VAST:
https://example.com/vast/v?price=${AUCTION_PRICE}
Scenario
- L'applicazione per le offerte OpenRTB include la macro
${AUCTION_PRICE}
nello snippet HTML o nell'URL VAST restituito a Google. - Google sostituisce il prezzo vincente della macro con una codifica Base64 sicura per il web non riempita (RFC 3548).
- Lo snippet passa la conferma nel formato scelto. Ad esempio, la conferma potrebbe essere passata nell'URL di una richiesta di pixel invisibile visualizzata nell'ambito dell'annuncio.
- Sul server, la tua applicazione decodifica le informazioni sul prezzo vincente e decripta il risultato in base64 web-safe.
Dipendenze
Avrai bisogno di una libreria di crittografia che supporti SHA-1 HMAC, ad esempio Openssl.
Codice di esempio
Il codice di esempio è fornito in Java e C++ e può essere scaricato dal progetto privatedatacommunicationprotocol.
Il codice di esempio Java utilizza il decodificatore base64 del progetto Apache Commons. Non è necessario scaricare il codice Apache Commons, poiché l'implementazione di riferimento include la parte necessaria ed è quindi autonoma.
Il codice di esempio C++ utilizza il metodo BIO base64 di OpenSSL. Prende una stringa sicura per il web codificata in base64 (RFC 3548) e la decodifica. In genere, le stringhe base64 sicure per il web sostituiscono il riempimento "=" con "." (tieni presente che le virgolette vengono aggiunte per una lettura più chiara e non sono incluse nel protocollo), ma la sostituzione della macro non riempie il prezzo criptato. L'implementazione di riferimento aggiunge il padding perché OpenSSL ha problemi con le stringhe non con padding.
Codifica
La crittografia e la decrittografia del prezzo vincente richiedono due chiavi segrete, 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 Authorized Buyers in Impostazioni
stimolante > 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 modo sicuro per il web e poi decodificate in base64 dall'applicazione:
e_key = WebSafeBase64Decode('skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=') i_key = WebSafeBase64Decode('arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=')
Schema di crittografia
Il prezzo viene criptato utilizzando uno schema di crittografia personalizzato progettato per minimizzare il sovraccarico delle dimensioni garantendo al contempo una sicurezza adeguata. Lo schema di crittografia utilizza un algoritmo HMAC con chiave per generare un padding segreto in base all'ID evento impressione unico.
Il prezzo criptato ha una lunghezza fissa di 28 byte. È costituito da un vettore di inizializzazione di 16 byte, 8 byte di testo crittografato e una firma di integrità di 4 byte. Il prezzo criptato è codificato in base64 sicuro per il web, in base a RFC 3548, con i caratteri di spaziatura interna omessi. Pertanto, il prezzo criptato di 28 byte viene codificato come stringa base64 sicura per il web di 38 caratteri, indipendentemente 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 calcolaHMAC(encryption_key,initialization_vector)
ed esegue 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.
Input | |
---|---|
iv |
vettore di inizializzazione (16 byte, univoco per l'impressione) |
e_key |
Chiave di crittografia (32 byte, fornita durante la configurazione dell'account) |
i_key |
Chiave di integrità (32 byte, fornita durante la 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 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 decriptazione
Il codice di decrittografia 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 ci sono limitazioni relative ai dettagli della struttura dell'implementazione. Nella maggior parte dei casi, dovresti essere in grado di prendere il codice di esempio e adattarlo alle tue esigenze.
Input | |
---|---|
e_key |
chiave di crittografia, 32 byte, fornita durante la configurazione dell'account |
i_key |
Chiave di integrità, 32 byte: fornita durante la configurazione dell'account |
final_message |
38 caratteri con codifica Base64 sicura per il web |
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) |
Rilevare attacchi con risposte non aggiornate
Per rilevare gli attacchi di replay o di risposta non aggiornata, ti consigliamo di filtrare le risposte con un timestamp molto diverso 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 crittografici per codificare e decodificare il prezzo vincente, puoi utilizzare DoubleClickCrypto.java. Per ulteriori informazioni, consulta la sezione Crittografia.