Cuando tu creatividad gana una subasta, Google puede informarte cuál fue el precio ganador si la creatividad incluye la macro ${AUCTION_PRICE}
.
Cuando se expande la macro, muestra el precio ganador en un formato encriptado. Se puede incluir en una creatividad, por ejemplo, con una solicitud de píxel invisible que se renderiza como parte del anuncio:
<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}
también se puede incluir en la URL de VAST de una creatividad de video, pero no en la URL de impresión en VAST:
https://example.com/vast/v?price=${AUCTION_PRICE}
Situación
- Tu aplicación de ofertas de OpenRTB incluye la macro
${AUCTION_PRICE}
en el fragmento HTML o la URL de VAST que devuelve a Google. - Google sustituye el precio ganador por la macro en la codificación Base64 segura para la Web sin padding (RFC 3548).
- El fragmento pasa la confirmación en el formato que elegiste. Por ejemplo, la confirmación se puede pasar en la URL de una solicitud de píxel invisible que se renderiza como parte del anuncio.
- En el servidor, la codificación base64 segura para la Web de tu aplicación decodifica la información del precio ganador y desencripta el resultado.
Dependencias
Necesitarás una biblioteca de criptografía que admita HMAC SHA-1, como Openssl.
Código de muestra
El código de muestra se proporciona en Java y C++, y se puede descargar desde el proyecto privatedatacommunicationprotocol.
El código de muestra de Java usa el decodificador base64 del proyecto de Apache Commons. No necesitarás descargar el código de Apache Commons, ya que la implementación de referencia incluye la parte necesaria y, por lo tanto, es independiente.
El código de muestra de C++ usa el método BIO de base64 de OpenSSL. Toma una cadena codificada en base64 segura para la Web (RFC 3548) y la decodifica. Por lo general, las cadenas Base64 seguras para la Web reemplazan el padding "=" por "." (ten en cuenta que se agregan comillas para mayor claridad de lectura y no se incluyen en el protocolo), pero la sustitución de macro no agrega padding al precio encriptado. La implementación de referencia agrega padding porque OpenSSL tiene problemas con cadenas sin padding.
Codificación
La encriptación y desencriptación del precio ganador requiere dos claves secretas, pero compartidas. Una clave de integridad y una clave de encriptación, que se denominan i_key
y e_key
, respectivamente. Ambas claves se proporcionan en la configuración de la cuenta como cadenas base64 seguras para la Web y se pueden encontrar en la página de Authorized Buyers, en Configuración del ofertante > Configuración de RTB > Claves de encriptación.
Ejemplos de claves de integridad y encriptación:
skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o= // Encryption key (e_key) arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo= // Integrity key (i_key)
Tu aplicación debe decodificar las claves de forma segura para la Web y, luego, decodificarlas en Base64:
e_key = WebSafeBase64Decode('skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=') i_key = WebSafeBase64Decode('arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=')
Esquema de encriptación
El precio se encripta con un esquema de encriptación personalizado diseñado para minimizar la sobrecarga de tamaño y, al mismo tiempo, garantizar una seguridad adecuada. El esquema de encriptación usa un algoritmo HMAC con clave para generar un pad secreto basado en el ID de evento de impresión único.
El precio encriptado tiene una longitud fija de 28 bytes. Se compone de un vector de inicialización de 16 bytes, 8 bytes de texto cifrado y una firma de integridad de 4 bytes. El precio encriptado está codificado en base64 seguro para la Web, según RFC 3548, y se omiten los caracteres de padding. Por lo tanto, el precio encriptado de 28 bytes se codifica como una cadena de Base64 segura para la Web de 38 caracteres, independientemente del precio ganador pagado.
Ejemplos de precios encriptados:
YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCce_6msaw // 100 CPI micros YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCAWJRxOgA // 1900 CPI micros YWJjMTIzZGVmNDU2Z2hpN7fhCuPemC32prpWWw // 2700 CPI micros
El formato encriptado es el siguiente:
{initialization_vector (16 bytes)}{encrypted_price (8 bytes)} {integrity (4 bytes)}
El precio está encriptado como <price xor HMAC(encryption_key,
initialization_vector)>
, por lo que la desencriptación calcula HMAC(encryption_key,initialization_vector)
y lo XOR con el precio encriptado para revertir la encriptación. La etapa de integridad toma 4 bytes de <HMAC(integrity_key, price||initialization_vector)>
, en los que ||
es la concatenación.
Entradas | |
---|---|
iv |
vector de inicialización (16 bytes, único para la impresión) |
e_key |
clave de encriptación (32 bytes, proporcionada durante la configuración de la cuenta) |
i_key |
clave de integridad (32 bytes, proporcionada durante la configuración de la cuenta) |
price |
(8 bytes, en micros de la moneda de la cuenta) |
Notation | |
hmac(k, d) |
HMAC SHA-1 de los datos d , con la clave k |
a || b |
cadena a concatenada con cadena 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 desencriptación
Tu código de desencriptación debe desencriptar el precio con la clave de encriptación y verificar los bits de integridad con la clave de integridad. Se te proporcionarán las claves durante la configuración. No hay restricciones sobre los detalles de cómo estructurar tu implementación. En general, deberías poder tomar el código de muestra y adaptarlo según tus necesidades.
Entradas | |
---|---|
e_key |
clave de encriptación, 32 bytes (se proporciona cuando se configura la cuenta) |
i_key |
clave de integridad, 32 bytes (se proporciona cuando se configura la cuenta) |
final_message |
38 caracteres codificados en base64 seguro para la Web |
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) |
Detecta ataques de respuesta inactiva
Para detectar ataques de respuesta inactiva o de repetición, se recomienda que filtres las respuestas con una marca de tiempo que difiera significativamente de la hora del sistema, después de tener en cuenta las diferencias de zona horaria.
El vector de inicialización contiene una marca de tiempo en los primeros 8 bytes. La siguiente función de C++ puede leerlo:
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) }
La marca de tiempo se puede convertir a un formato legible por humanos con el siguiente código en 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 de Java
En lugar de implementar los algoritmos de criptografía para codificar y decodificar el precio ganador, puedes usar DoubleClickCrypto.java. Para obtener más información, consulta Criptografía.