Когда ваш креатив побеждает на аукционе, Google может сообщить вам, какая цена была выиграна, если фрагмент HTML или URL-адрес VAST, определяющий креатив, содержит макрос WINNING_PRICE
. Google возвращает выигрышную цену в зашифрованном виде. В следующих разделах объясняется, как ваше приложение может расшифровать информацию о выигрышной цене.
Макрос WINNING_PRICE
можно включить в креатив, например, с запросом невидимого пикселя, отображаемым как часть объявления:
<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>
Макрос WINNING_PRICE
также можно включить в URL-адрес VAST видеокреатива (но не в URL-адрес показа в VAST):
https://example.com/vast/v?price=%%WINNING_PRICE%%
Сценарий
- Ваше приложение включает макрос
WINNING_PRICE
во фрагмент HTML или URL-адрес VAST, который оно возвращает в Google. - Google заменяет выигрышную цену на макрос в незаполненной веб-безопасной кодировке base64 ( RFC 3548 ).
- Фрагмент проходит подтверждение в выбранном вами формате. Например, подтверждение может быть передано в URL запроса невидимого пикселя, отображаемого как часть объявления.
- На сервере ваше веб-приложение base64 декодирует информацию о выигрышной цене и расшифровывает результат.
Зависимости
Вам понадобится криптобиблиотека, поддерживающая SHA-1 HMAC, например Openssl.
Образец кода
Пример кода предоставляется на Java и C++ и может быть загружен из проекта privatedatacommunicationprotocol .
Пример кода Java использует декодер base64 из проекта Apache commons . Вам не нужно будет загружать общедоступный код Apache, так как эталонная реализация включает в себя необходимую часть и поэтому является автономной.
В примере кода C++ используется метод OpenSSL base64 BIO . Он берет строку в кодировке base64 ( RFC 3548 ) и декодирует ее. Обычно строки base64, безопасные для Интернета, заменяют отступы "=" на "." (обратите внимание, что кавычки добавлены для ясности чтения и не включены в протокол), но подстановка макроса не дополняет зашифрованную цену. Эталонная реализация добавляет заполнение, потому что у OpenSSL есть проблемы со строками без дополнений.
Кодирование
Шифрование и дешифрование выигрышной цены требуют двух секретных, но общих ключей. Ключ целостности и ключ шифрования, обозначаемые как i_key
и e_key
соответственно. Оба ключа предоставляются при настройке учетной записи в виде безопасных для Интернета строк base64.
Пример ключей целостности и шифрования:
skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o= // Encryption key (e_key) arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo= // Integrity key (i_key)
Ключи должны быть декодированы в веб-безопасности, а затем вашим приложением декодировано base64:
e_key = WebSafeBase64Decode('skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=') i_key = WebSafeBase64Decode('arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=')
Схема шифрования
Цена зашифрована с использованием пользовательской схемы шифрования, которая предназначена для минимизации накладных расходов при обеспечении надлежащей безопасности. Схема шифрования использует алгоритм HMAC с ключом для создания секретной панели на основе уникального идентификатора события показа.
Зашифрованная цена имеет фиксированную длину 28 байт. Он состоит из 16-байтового вектора инициализации, 8 байтов зашифрованного текста и 4-байтовой подписи целостности. Зашифрованная цена представляет собой веб-безопасную кодировку base64 в соответствии с RFC 3548 с опущенными символами заполнения. Таким образом, 28-байтовая зашифрованная цена кодируется как 38-символьная веб-безопасная строка base-64, независимо от уплаченной выигрышной цены.
Пример зашифрованных цен:
YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCce_6msaw // 100 CPI micros YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCAWJRxOgA // 1900 CPI micros YWJjMTIzZGVmNDU2Z2hpN7fhCuPemC32prpWWw // 2700 CPI micros
Зашифрованный формат:
{initialization_vector (16 bytes)}{encrypted_price (8 bytes)} {integrity (4 bytes)}
Цена зашифрована как <price xor HMAC(encryption_key, initialization_vector)>
, поэтому при расшифровке вычисляются HMAC(encryption_key,initialization_vector)
и xor с зашифрованной ценой для обратного шифрования. Стадия целостности занимает 4 байта <HMAC(integrity_key, price||initialization_vector)>
где ||
является конкатенация.
Входы | |
---|---|
iv | вектор инициализации (16 байт - уникальный для оттиска) |
e_key | ключ шифрования (32 байта — предоставляется при настройке учетной записи) |
i_key | ключ целостности (32 байта — предоставляется при настройке учетной записи) |
price | (8 байт - в микро валюте счета) |
Обозначение | |
hmac(k, d) | SHA-1 HMAC данных d с использованием ключа k |
a || b | строка a объединенная со строкой b |
Псевдокод | |
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 ) |
Схема расшифровки
Ваш код дешифрования должен расшифровать цену с помощью ключа шифрования и проверить биты целостности с помощью ключа целостности. Ключи будут предоставлены вам во время установки. Нет никаких ограничений на детали того, как вы структурируете свою реализацию. По большей части вы должны быть в состоянии взять пример кода и адаптировать его в соответствии с вашими потребностями.
Входы | |
---|---|
e_key | ключ шифрования, 32 байта - предоставляется при настройке учетной записи |
i_key | ключ целостности, 32 байта - предоставляется при настройке учетной записи |
final_message | 38 символов, безопасных для Интернета, в кодировке base64 |
Псевдокод | |
// 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) |
Обнаружение атак с устаревшим ответом
Для обнаружения устаревших ответов или повторных атак рекомендуется фильтровать ответы с отметкой времени, которая значительно отличается от системного времени, после учета разницы часовых поясов.
Вектор инициализации содержит метку времени в первых 8 байтах. Его можно прочитать с помощью следующей функции 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) }
Отметку времени можно преобразовать в удобочитаемую форму с помощью следующего кода 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);
Java-библиотека
Вместо реализации криптоалгоритмов для кодирования и декодирования выигрышной цены вы можете использовать DoubleClickCrypto.java . Дополнительные сведения см. в разделе Криптография .