Gdy Twoja kreacja wygra aukcję, Google może poinformować Cię o wygrywającej cenie, jeśli zawiera ona makro ${AUCTION_PRICE}
.
Po rozwinięciu makro zwraca zwycięską cenę w zaszyfrowanej formie. Może ono być uwzględnione w kreacji, np. za pomocą żądania niewidocznego piksela renderowanego jako część reklamy:
<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}
może też występować w adresie URL VAST kreacji wideo, ale nie w adresie URL wyświetlenia w VAST:
https://example.com/vast/v?price=${AUCTION_PRICE}
Scenariusz
- Twoja aplikacja do określania stawek za pomocą OpenRTB zawiera makro
${AUCTION_PRICE}
w fragmentie kodu HTML lub adresie URL VAST zwracanym do Google. - Google zastępuje wygraną cenę w makro za pomocą niewypełnionego kodowania base64 bezpiecznego dla sieci (RFC 3548).
- Fragment kodu przekazuje potwierdzenie w wybranym formacie. Potwierdzenia można na przykład przekazywać w adresie URL żądania niewidocznego piksela renderowanego w ramach reklamy.
- Na serwerze aplikacja dekoduje informacje o zwycięskiej cenie za pomocą funkcji base64 w formacie web-safe i odszyfrowuje wynik.
Zależności
Potrzebna będzie biblioteka kryptograficzna obsługująca SHA-1 HMAC, np. Openssl.
Przykładowy kod
Przykładowy kod jest dostępny w językach Java i C++. Można go pobrać z projektu privatedatacommunicationprotocol.
Przykładowy kod w Javie korzysta z dekodera base64 z projektu Apache Commons. Nie musisz pobierać kodu Apache Commons, ponieważ implementacja referencyjna zawiera niezbędne części i jest więc samowystarczalna.
Przykładowy kod C++ korzysta z metody base64 BIO OpenSSL. Dekoduje ciąg znaków zakodowany w standardzie base64 (RFC 3548) i przekształca go w tekst. Zwykle ciągi tekstowe Base64 bezpieczne dla stron internetowych zastępują wypełnienie „="” przez „". (Uwaga: cudzysłówy są dodawane w celu ułatwienia czytania i nie są uwzględniane w protokole), ale zastąpienie za pomocą makra nie wypełnia zaszyfrowanej ceny. Implementacja referencyjna dodaje wypełnienie, ponieważ OpenSSL ma problemy z niewypełnionymi ciągami znaków.
Kodowanie
Szyfrowanie i odszyfrowywanie zwycięskich cen wymaga użycia 2 tajnych, ale udostępnionych kluczy. Klucz integralności i klucz szyfrowania, odpowiednio i_key
i e_key
. Oba klucze są udostępniane podczas konfigurowania konta w postaci bezpiecznych dla sieci ciągów znaków w formacie base64. Znajdziesz je na stronie Authorized Buyers w sekcji Ustawienia systemu licytującego > Ustawienia RTB > Klucze szyfrowania.
Przykłady kluczy integralności i szyfrowania:
skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o= // Encryption key (e_key) arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo= // Integrity key (i_key)
Klucze powinny być najpierw zdekodowane w bezpiecznym formacie internetowym, a potem zdekodowane w formacie base64 przez aplikację:
e_key = WebSafeBase64Decode('skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=') i_key = WebSafeBase64Decode('arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=')
Schemat szyfrowania
Cena jest szyfrowana za pomocą niestandardowego schematu szyfrowania, który ma na celu zminimalizowanie rozmiaru obciążenia przy jednoczesnym zapewnieniu odpowiedniego poziomu bezpieczeństwa. Schemat szyfrowania używa algorytmu HMAC z kluczem, aby wygenerować tajny blok na podstawie unikalnego identyfikatora zdarzenia wyświetlenia.
Zaszyfrowana cena ma stałą długość 28 bajtów. Składa się z 16-bajtowego wektora inicjującego, 8-bajtowego tekstu zaszyfrowanego i 4-bajtowego podpisu integralności. Zaszyfrowana cena jest zakodowana w formacie base64 zgodnym ze standardem RFC 3548, z pominięciem znaków wypełnienia. W związku z tym zaszyfrowana cena o długości 28 bajtów jest kodowana jako ciąg znaków o długości 38 znaków w formacie Base64, niezależnie od wygranej ceny.
Przykłady zaszyfrowanych cen:
YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCce_6msaw // 100 CPI micros YWJjMTIzZGVmNDU2Z2hpN7fhCuPemCAWJRxOgA // 1900 CPI micros YWJjMTIzZGVmNDU2Z2hpN7fhCuPemC32prpWWw // 2700 CPI micros
Zaszyfrowany format:
{initialization_vector (16 bytes)}{encrypted_price (8 bytes)} {integrity (4 bytes)}
Cena jest zaszyfrowana jako <price xor HMAC(encryption_key,
initialization_vector)>
, więc deszyfrowanie oblicza HMAC(encryption_key,initialization_vector)
i xoruje z zaszyfrowaną ceną, aby odwrócić szyfrowanie. Etap integralności zajmuje 4 bajty <HMAC(integrity_key, price||initialization_vector)>
, gdzie ||
to konkatenacja.
Wejścia | |
---|---|
iv |
wektor inicjujący (16 bajtów – unikalny dla danego wyświetlenia); |
e_key |
klucz szyfrowania (32 bajty – podany podczas konfigurowania konta); |
i_key |
klucz integralności (32 bajty – podany podczas konfigurowania konta); |
price |
(8 bajtów – w mikrowalucie konta) |
Notacja | |
hmac(k, d) |
HMAC SHA-1 danych d , przy użyciu klucza k |
a || b |
ciąg tekstowy a złączony z ciągiem tekstowym b |
Pseudokod | |
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 ) |
Schemat odszyfrowywania
Kod odszyfrowywania musi odszyfrować cenę za pomocą klucza szyfrowania i zweryfikować bity integralności za pomocą klucza integralności. Klucze zostaną udostępnione podczas konfiguracji. Nie ma żadnych ograniczeń dotyczących szczegółów struktury implementacji. W większości przypadków możesz pobrać przykładowy kod i dostosować go do swoich potrzeb.
Wejścia | |
---|---|
e_key |
klucz szyfrowania (32 bajty) – podany podczas konfigurowania konta; |
i_key |
klucz integralności, 32 bajty – podany podczas konfigurowania konta; |
final_message |
38 znaków, obsługiwana w internecie i zakodowana w base64 |
Pseudokod | |
// 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) |
Wykrywanie ataków z nieaktualnymi odpowiedziami
Aby wykrywać nieaktualne odpowiedzi lub ataki polegające na powtórzeniu odpowiedzi, zalecamy odfiltrowywanie odpowiedzi z sygnaturą czasową, która znacznie różni się od czasu systemowego, uwzględniając różnice w strefach czasowych.
Wektor inicjowania zawiera sygnaturę czasową w pierwszych 8 bajtach. Może być odczytywany przez tę funkcję 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) }
Czas można przekonwertować na czytelną dla człowieka postać za pomocą tego kodu 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);
Biblioteka Java
Zamiast implementować algorytmy kryptograficzne do kodowania i dekodowania ceny zwycięskiej oferty, możesz użyć pliku DoubleClickCrypto.java. Więcej informacji znajdziesz w artykule Kryptografia.