Расшифровка ценовых подтверждений

Когда ваше объявление выигрывает аукцион, 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%%

Сценарий

  1. Ваше приложение включает макрос WINNING_PRICE во фрагмент HTML или URL-адрес VAST, который он возвращает в Google.
  2. Google заменяет выигрышную цену макроса недополненной веб-безопасной кодировкой Base64 ( RFC 3548 ).
  3. Фрагмент передает подтверждение в выбранном вами формате. Например, подтверждение может быть передано в URL-адресе запроса невидимого пикселя, отображаемого как часть объявления.
  4. На сервере ваше веб-приложение 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. Их можно найти на странице «Авторизованные покупатели» в разделе «Настройки участника аукциона» > «Настройки RTB» > «Ключи шифрования» .

Пример ключей целостности и шифрования:

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 . Дополнительные сведения см. в разделе Криптография .