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

Оптимизируйте свои подборки Сохраняйте и классифицируйте контент в соответствии со своими настройками.

Когда ваш креатив побеждает на аукционе, 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.

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

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