Gdy kreacja wygra aukcję, Google może poinformować Cię, jaka była zwycięska cena, jeśli fragment kodu HTML lub adres URL VAST, który ją definiuje, zawiera makro WINNING_PRICE
. Google zwraca zwycięską cenę w postaci zaszyfrowanej. W sekcjach poniżej wyjaśniono, jak aplikacja może odszyfrować informacje o zwycięskiej cenie.
Makro WINNING_PRICE
można umieścić w kreacji, np. w przypadku renderowania niewidocznego żądania piksela:
<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>
Makro WINNING_PRICE
można też umieścić w adresie URL VAST kreacji wideo (ale nie w adresie URL wyświetlenia w VAST):
https://example.com/vast/v?price=%%WINNING_PRICE%%
Scenariusz
- Aplikacja umieszcza makro
WINNING_PRICE
we fragmencie kodu HTML lub adresie URL VAST zwracanym do Google. - Google zastępuje zwycięską cenę makro za pomocą niedopełnionego kodowania base64 i bezpiecznego dla stron internetowych (RFC 3548).
- Fragment kodu przekazuje potwierdzenie w wybranym formacie. Potwierdzenie może być na przykład przekazywane w adresie URL niewidocznego żądania piksela renderowanego w ramach reklamy.
- Na serwerze bezpieczna w internecie aplikacja base64 dekoduje informacje o zwycięskiej cenie i odszyfrowuje wynik.
Zależności
Potrzebujesz biblioteki kryptograficznej obsługującej protokół HMAC SHA-1, np. Openssl.
Przykładowy kod
Przykładowy kod jest udostępniony w języku Java i C++ i 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ędną część i jest samodzielna.
W przykładowym kodzie C++ użyto metody OpenSSL base64 BIO. Wykorzystuje do tego bezpieczny w internecie ciąg zakodowany w standardzie base64 (RFC 3548) i dekoduje go. Normalnie ciągi base64 przeznaczone do użytku w internecie zastępują dopełnienie „=” znakiem „.” (pamiętaj, że dla ułatwienia odczytu znaki cudzysłowu są dodawane, ale nie są uwzględnione w protokole), ale zastępowanie makrem nie zakłóca zaszyfrowanej ceny. Implementacja referencyjna dodaje dopełnienie, ponieważ OpenSSL ma problemy z ciągami znaków bez dopełnienia.
Kodowanie
Szyfrowanie i odszyfrowywanie zwycięskiej ceny wymaga 2 tajnych, ale wspólnych kluczy. Klucz integralności i klucz szyfrowania – odpowiednio i_key
i e_key
. Oba klucze są udostępniane podczas konfiguracji konta jako bezpieczne w internecie ciągi znaków base64. Można je znaleźć na stronie Authorized Buyers w sekcji Ustawienia systemu licytującego > Ustawienia RTB > Klucze szyfrowania.
Przykładowe klucze integralności i szyfrowania:
skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o= // Encryption key (e_key) arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo= // Integrity key (i_key)
Klucze powinny być dekodowane do bezpiecznego internetu, a następnie dekodowane w formacie base64 przez aplikację:
e_key = WebSafeBase64Decode('skU7Ax_NL5pPAFyKdkfZjZz2-VhIN8bjj1rVFOaJ_5o=') i_key = WebSafeBase64Decode('arO23ykdNqUQ5LEoQ0FVmPkBd7xB5CO89PDZlSjpFxo=')
Schemat szyfrowania
Cena jest szyfrowana z użyciem niestandardowego schematu szyfrowania, który ma na celu ograniczenie obciążenia i zapewnienie odpowiednich bezpieczeństwa. Schemat szyfrowania wykorzystuje algorytm HMAC z kluczem, aby wygenerować tajny klucz 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 bajtów tekstu szyfrowanego i 4-bajtowej sygnatury integralności. Zaszyfrowana cena jest zakodowana w internecie zgodnie z RFC 3548 w standardzie base64 z pominięciem znaków dopełniających. Tak więc 28-bajtowa szyfrowana cena jest kodowana jako 38-znakowy ciąg tekstowy w formacie base-64 przeznaczonym do bezpiecznego przesyłania w internecie, niezależnie od zapłaconej ceny.
Przykładowe zaszyfrowane ceny:
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 podczas odszyfrowywania oblicza się wartość HMAC(encryption_key,initialization_vector)
, a xor z zaszyfrowaną ceną, aby cofnąć szyfrowanie. Na etapie integralności są 4 bajty <HMAC(integrity_key, price||initialization_vector)>
, gdzie ||
to konkatenacja.
Dane wejściowe | |
---|---|
iv |
wektor inicjujący (16 bajtów – unikalny dla 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 milionowych częściach waluty konta) |
Zapis | |
hmac(k, d) |
HMAC SHA-1 danych d przy użyciu klucza k |
a || b |
ciąg tekstowy a połączony z ciągiem znaków 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
Twój kod odszyfrowywania musi odszyfrować cenę za pomocą klucza szyfrowania i zweryfikować bity integralności kluczem integralności. Klucze zostaną Ci udostępnione podczas konfiguracji. Nie ma żadnych ograniczeń dotyczących struktury implementacji. Najczęstszą częścią tego rozwiązania jest wykorzystanie przykładowego kodu i dostosowanie go do swoich potrzeb.
Dane wejściowe | |
---|---|
e_key |
klucz szyfrowania o długości 32 bajtów – dostarczony podczas konfigurowania konta |
i_key |
klucz integralności, 32 bajty – dostarczony podczas konfigurowania konta |
final_message |
38 znaków, przeznaczone do bezpieczeństwa w internecie, zakodowane 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 nieaktualnych odpowiedzi
Aby wykrywać nieaktualne odpowiedzi lub ponowne próby ataków, zalecamy odfiltrowanie odpowiedzi z sygnaturą czasową, która znacznie różni się od czasu systemowego, uwzględniając różnice między strefami czasowymi.
Wektor inicjujący zawiera sygnaturę czasową w pierwszych 8 bajtach. Można go odczytać za pomocą tej funkcji 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) }
Sygnaturę czasową można przekształcić do postaci czytelnej dla człowieka za pomocą tego kodu w języku 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 w celu kodowania i dekodowania zwycięskiej ceny, możesz użyć pliku DoubleClickCrypto.java. Więcej informacji znajdziesz w sekcji Kryptografia.