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

Когда ваш креатив выигрывает аукцион, Google может сообщить вам выигрышную цену, если креатив содержит соответствующий макрос.

Если ваша система назначения ставок настроена на использование протокола OpenRTB, креатив, включенный в вашу ставку, должен использовать макрос ${AUCTION_PRICE} IAB.

Если ваша система назначения ставок использует устаревший протокол Google RTB, в креативе должен использоваться макрос Google %%WINNING_PRICE%% .

Когда эти макросы развернуты, они возвращают выигрышную цену в зашифрованном виде. Их можно включить в креатив, например, с помощью запроса невидимого пикселя, отображаемого как часть объявления:

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

Макрос ${AUCTION_PRICE} также можно включить в URL-адрес VAST видеообъявления, но не в URL-адрес показа в VAST:

https://example.com/vast/v?price=${AUCTION_PRICE}

Сценарий

  1. Ваше приложение для назначения ставок OpenRTB включает макрос ${AUCTION_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 . Дополнительные сведения см. в разделе Криптография .