Mendekripsi Informasi Harga

Saat materi iklan Anda memenangkan lelang, Google dapat memberi tahu Anda harga pemenang jika materi iklan menyertakan makro ${AUCTION_PRICE}.

Saat diperluas, makro akan menampilkan harga pemenang dalam bentuk terenkripsi. Piksel ini dapat disertakan dalam materi iklan, misalnya, dengan permintaan piksel tidak terlihat yang dirender sebagai bagian dari iklan:

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

Makro ${AUCTION_PRICE} juga dapat disertakan dalam URL VAST materi iklan video, tetapi tidak dalam URL tayangan di VAST:

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

Skenario

  1. Aplikasi bidding OpenRTB Anda menyertakan makro ${AUCTION_PRICE} dalam cuplikan HTML atau URL VAST yang ditampilkan ke Google.
  2. Google mengganti harga pemenang untuk makro dalam encoding base64 yang aman bagi web tanpa padding (RFC 3548).
  3. Cuplikan meneruskan konfirmasi dalam format yang telah Anda pilih. Misalnya, konfirmasi mungkin diteruskan di URL permintaan piksel yang tidak terlihat yang dirender sebagai bagian dari iklan.
  4. Di server, base64 aman web aplikasi Anda mendekode informasi harga pemenang dan mendekripsi hasilnya.

Dependensi

Anda memerlukan library kripto yang mendukung SHA-1 HMAC, seperti Openssl.

Kode contoh

Kode contoh disediakan dalam Java dan C++ dan dapat didownload dari project privatedatacommunicationprotocol.

  • Kode contoh Java menggunakan dekoder base64 dari project Apache commons. Anda tidak perlu mendownload kode Apache commons, karena implementasi referensi menyertakan bagian yang diperlukan sehingga bersifat mandiri.

  • Kode contoh C++ menggunakan metode BIO base64 OpenSSL. Fungsi ini mengambil string yang dienkode base64 yang sesuai untuk web (RFC 3548) dan mendekodenya. Biasanya, string base64 yang aman untuk web mengganti padding "=" dengan "." (perhatikan bahwa tanda kutip ditambahkan untuk kejelasan pembacaan dan tidak disertakan dalam protokol), tetapi penggantian makro tidak mengisi harga terenkripsi. Implementasi referensi menambahkan padding karena OpenSSL mengalami masalah dengan string tanpa padding.

Encoding

Enkripsi dan dekripsi harga pemenang memerlukan dua kunci rahasia, tetapi bersama. Kunci integritas, dan kunci enkripsi, masing-masing disebut sebagai i_key, dan e_key. Kedua kunci tersebut diberikan saat penyiapan akun sebagai string base64 yang aman untuk web, dan dapat ditemukan di halaman Authorized Buyers di bagian Setelan bidder > Setelan RTB > Kunci enkripsi.

Contoh kunci integritas dan enkripsi:

skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=  // Encryption key (e_key)
arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=  // Integrity key (i_key)

Kunci harus didekode dengan aman untuk web, lalu didekode base64 oleh aplikasi Anda:

e_key = WebSafeBase64Decode('skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=')
i_key = WebSafeBase64Decode('arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=')

Skema enkripsi

Harga dienkripsi menggunakan skema enkripsi kustom yang dirancang untuk meminimalkan overhead ukuran sekaligus memastikan keamanan yang memadai. Skema enkripsi menggunakan algoritma HMAC dengan kunci untuk menghasilkan secret pad berdasarkan ID peristiwa tayangan iklan yang unik.

Harga terenkripsi memiliki panjang tetap 28 byte. Ini terdiri dari vektor inisialisasi 16 byte, 8 byte ciphertext, dan tanda tangan integritas 4 byte. Harga terenkripsi dienkode dalam base64 yang sesuai untuk web, sesuai dengan RFC 3548, dengan karakter padding dihilangkan. Dengan demikian, harga terenkripsi 28 byte dienkode sebagai string base-64 38 karakter yang aman bagi web, terlepas dari harga pemenang yang dibayar.

Contoh harga terenkripsi:

YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCce_6msaw  // 100 CPI micros
YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCAWJRxOgA  // 1900 CPI micros
YWJjMTIzZGVmNDU2Z2hpN7fhCuPemC32prpWWw  // 2700 CPI micros

Format terenkripsi adalah:

{initialization_vector (16 bytes)}{encrypted_price (8 bytes)}
{integrity (4 bytes)}

Harga dienkripsi sebagai <price xor HMAC(encryption_key, initialization_vector)> sehingga dekripsi menghitung HMAC(encryption_key,initialization_vector) dan xor dengan harga terenkripsi untuk membalikkan enkripsi. Tahap integritas memerlukan 4 byte <HMAC(integrity_key, price||initialization_vector)> dengan || adalah penyambungan.

Input
iv initialization vector (16 byte - unik untuk tayangan)
e_key kunci enkripsi (32 byte - diberikan saat penyiapan akun)
i_key kunci integritas (32 byte - diberikan saat penyiapan akun)
price (8 byte - dalam mikro mata uang akun)
Notasi
hmac(k, d) HMAC SHA-1 data d, menggunakan kunci k
a || b string a yang digabungkan dengan string b
Kode semu
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 )

Skema dekripsi

Kode dekripsi Anda harus mendekripsi harga menggunakan kunci enkripsi, dan memverifikasi bit integritas dengan kunci integritas. Kunci akan diberikan kepada Anda selama penyiapan. Tidak ada batasan pada detail cara Anda menstrukturkan penerapan. Pada umumnya, Anda dapat mengambil kode contoh dan menyesuaikannya sesuai kebutuhan.

Input
e_key kunci enkripsi, 32 byte - diberikan saat penyiapan akun
i_key kunci integritas, 32 byte - diberikan saat penyiapan akun
final_message 38 karakter yang dienkode dalam base64 yang sesuai untuk web
Kode semu
// 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)

Mendeteksi serangan respons yang sudah tidak berlaku

Untuk mendeteksi serangan replay atau respons yang sudah tidak berlaku, sebaiknya Anda memfilter respons dengan stempel waktu yang berbeda secara signifikan dengan waktu sistem, setelah memperhitungkan perbedaan zona waktu.

Vektor inisialisasi berisi stempel waktu dalam 8 byte pertama. File ini dapat dibaca oleh fungsi C++ berikut:

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

Stempel waktu dapat dikonversi ke bentuk yang dapat dibaca manusia menggunakan kode C++ berikut:

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

Library Java

Daripada menerapkan algoritma kripto untuk mengenkode dan mendekode harga pemenang, Anda dapat menggunakan DoubleClickCrypto.java. Untuk mengetahui informasi selengkapnya, lihat Kriptografi.