Preisbestätigungen entschlüsseln

Wenn Ihr Creative eine Auktion gewinnt, kann Google Ihnen den Preis für das erfolgreiche Gebot mitteilen. Dazu muss im HTML-Snippet oder der VAST-URL, die das Creative definiert, das Makro WINNING_PRICE enthalten sein. Google gibt den Preis für das erfolgreiche Gebot in verschlüsselter Form zurück. In den folgenden Abschnitten wird erläutert, wie Ihre Anwendung die Informationen zum erfolgreichen Preis entschlüsseln kann.

Das WINNING_PRICE-Makro kann in ein Creative aufgenommen werden, beispielsweise mit einer unsichtbaren Pixelanfrage, die als Teil der Anzeige gerendert wird:

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

Das WINNING_PRICE-Makro kann auch in die VAST-URL eines Video-Creatives aufgenommen werden, jedoch nicht in die Impressions-URL im VAST:

https://example.com/vast/v?price=%%WINNING_PRICE%%

Szenario

  1. Ihre App enthält das WINNING_PRICE-Makro im HTML-Snippet oder in der VAST-URL, die an Google zurückgegeben wird.
  2. Google ersetzt das Makro durch den Preis für das erfolgreiche Gebot in websicherer Base64-Codierung ohne Padding (RFC 3548).
  3. Das Snippet übergibt die Bestätigung in dem von Ihnen ausgewählten Format. Die Bestätigung kann beispielsweise in der URL einer Anfrage für unsichtbare Pixel übergeben werden, die als Teil der Anzeige gerendert wird.
  4. Auf dem Server decodiert die websichere Base64-Anwendung die Informationen zum erfolgreichen Preis und entschlüsselt das Ergebnis.

Abhängigkeiten

Sie benötigen eine Krypto-Bibliothek, die SHA-1 HMAC unterstützt, z. B. Openssl.

Beispielcode

Der Beispielcode wird in Java und C++ bereitgestellt und kann aus dem Projekt „privatedatacommunicationprotocol“ heruntergeladen werden.

  • Im Java-Beispielcode wird der Base64-Decoder aus dem Apache Commons-Projekt verwendet. Sie müssen den Apache Commons-Code nicht herunterladen, da die Referenzimplementierung den erforderlichen Teil enthält und daher eigenständig ist.

  • Der C++-Beispielcode verwendet die OpenSSL-base64-BIO-Methode. Dabei wird ein websicherer base64-codierter String (RFC 3548) decodiert. Normalerweise wird „=“ in websicheren Base64-Strings durch „.“ ersetzt. Anführungszeichen werden zum besseren Verständnis hinzugefügt und sind nicht im Protokoll enthalten. Durch die Ersetzung des Makros wird der verschlüsselte Preis jedoch nicht aufgefüllt. Bei der Referenzimplementierung wird ein Innenrand hinzugefügt, da OpenSSL Probleme mit nicht aufgefüllten Strings hat.

Codierung

Für die Verschlüsselung und Entschlüsselung des Höchstgebots sind zwei geheime, aber freigegebene Schlüssel erforderlich. Ein Integritätsschlüssel und ein Verschlüsselungsschlüssel, die als i_key bzw. e_key bezeichnet werden. Beide Schlüssel werden bei der Kontoeinrichtung als websichere Base64-Strings bereitgestellt und sind auf der Authorized Buyers-Seite unter Einstellungen der Gebotsfunktion > Einstellungen für Echtzeitgebote > Verschlüsselungsschlüssel zu finden.

Beispiele für Integritäts- und Verschlüsselungsschlüssel:

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

Schlüssel sollten websicher decodiert und dann von Ihrer Anwendung base64-decodiert werden:

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

Verschlüsselungsschema

Der Preis wird mit einem benutzerdefinierten Verschlüsselungsschema verschlüsselt, das den Größenaufwand minimiert und gleichzeitig eine angemessene Sicherheit gewährleistet. Das Verschlüsselungsschema verwendet einen schlüsselbasierten HMAC-Algorithmus, um ein geheimes Pad basierend auf der eindeutigen Impressionsereignis-ID zu generieren.

Der verschlüsselte Preis hat eine feste Länge von 28 Byte. Sie besteht aus einem 16-Byte-Initialisierungsvektor, 8 Byte Geheimtext und einer 4-Byte-Integritätssignatur. Der verschlüsselte Preis ist gemäß RFC 3548 websicher mit Base64 codiert, wobei die Padding-Zeichen weggelassen werden. Daher wird der verschlüsselte 28-Byte-Preis als websicherer Base64-String mit 38 Zeichen codiert, unabhängig vom bezahlten Zuschlagspreis.

Beispiele für verschlüsselte Preise:

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

Das verschlüsselte Format lautet:

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

Der Preis wird als <price xor HMAC(encryption_key, initialization_vector)> verschlüsselt, sodass bei der Entschlüsselung HMAC(encryption_key,initialization_vector) und xor mit dem verschlüsselten Preis berechnet werden, um die Verschlüsselung umzukehren. Die Integritätsphase benötigt 4 Byte von <HMAC(integrity_key, price||initialization_vector)>, wobei || die Verkettung ist.

Eingaben
iv Initialisierungsvektor (16 Byte – für die Impression eindeutig)
e_key Verschlüsselungsschlüssel (32 Byte – bei der Kontoeinrichtung bereitgestellt)
i_key Integritätsschlüssel (32 Byte – bei Kontoeinrichtung bereitgestellt)
price (8 Byte – in Mikroeinheiten der Kontowährung)
Notation
hmac(k, d) SHA-1-HMAC der Daten d, mit dem Schlüssel k
a || b String a, verkettet mit String b
Pseudocode
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 )

Entschlüsselungsmethode

Ihr Entschlüsselungscode muss den Preis mit dem Verschlüsselungsschlüssel entschlüsseln und die Integritätsbits mit dem Integritätsschlüssel verifizieren. Sie erhalten die Schlüssel bei der Einrichtung. Es gibt keine Einschränkungen hinsichtlich der Strukturierung Ihrer Implementierung. Sie sollten größtenteils in der Lage sein, den Beispielcode an Ihre Anforderungen anzupassen.

Eingaben
e_key Verschlüsselungsschlüssel, 32 Byte – bei der Kontoeinrichtung bereitgestellt
i_key Integritätsschlüssel, 32 Byte – bei Kontoeinrichtung bereitgestellt
final_message 38 Zeichen websicher Base64-codiert
Pseudocode
// 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)

Angriffe auf veraltete Antworten erkennen

Zur Erkennung veralteter Antworten oder Replay-Angriffe wird empfohlen, nach Berücksichtigung von Zeitzonenunterschieden Antworten mit einem Zeitstempel zu filtern, der erheblich von der Systemzeit abweicht.

Der Initialisierungsvektor enthält in den ersten 8 Byte einen Zeitstempel. Er kann mit der folgenden C++-Funktion gelesen werden:

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

Der Zeitstempel kann mithilfe des folgenden C++-Codes in eine visuell lesbare Form konvertiert werden:

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

Anstatt die Krypto-Algorithmen zum Codieren und Decodieren des erfolgreichen Preises zu implementieren, können Sie auch DoubleClickCrypto.java verwenden. Weitere Informationen finden Sie unter Kryptografie.