Werbenetzwerke, in denen
JavaScript-Tags zum Füllen von Anzeigen über Authorized Buyers verwendet werden, können Werbetreibenden-IDs sowohl für Android- als auch für iOS-Geräte empfangen.
Die Informationen werden über das Makro %%EXTRA_TAG_DATA%%
oder %%ADVERTISING_IDENTIFIER%%
im von Authorized Buyers verwalteten JavaScript-Tag gesendet. Der Rest dieses Abschnitts konzentriert sich auf die Extraktion von %%EXTRA_TAG_DATA%%
. Unter
Remarketing mit IDFA oder Werbe-ID finden Sie jedoch weitere Informationen zum %%ADVERTISING_IDENTIFIER%%
-verschlüsselten Proto-Zwischenspeicher MobileAdvertisingId
, der entsprechend entschlüsselt werden kann.
Zeitplan
- Die JavaScript-In-App-Tags des Werbenetzwerks werden über die Authorized Buyers-Benutzeroberfläche aktualisiert und über das
%%EXTRA_TAG_DATA%%
-Makro wie unten beschrieben hinzugefügt. - Bei der Auslieferung fordert die App über das Google Mobile Ads SDK eine Anzeige von Authorized Buyers an und übergibt die Werbetreibenden-ID sicher.
- Die App empfängt das JavaScript-Tag und das Makro
%%EXTRA_TAG_DATA%%
wird mit dem verschlüsselten Protokollzwischenspeicher des Werbenetzwerks ausgefüllt, der diese ID enthält. - Die App führt dieses Tag aus und sendet einen Aufruf an das Werbenetzwerk für die erfolgreiche Anzeige.
- Zur Verwendung (Monetarisierung) dieser Informationen muss das Werbenetzwerk den Protokollpuffer verarbeiten:
- Decodieren Sie den websicheren String mit WebSafeBase64 wieder in einen Bytestring.
- Entschlüsseln Sie sie mit dem unten beschriebenen Schema.
- Deserialisieren Sie das Protokoll und rufen Sie die Werbetreibenden-ID aus ExtraTagData.advertising_id oder ExtraTagData.hashed_idfa ab.
Abhängigkeiten
- Den WebSafeBase64-Encoder
- Eine Kryptobibliothek, die SHA-1 HMAC unterstützt, z. B. Openssl.
- Den Protokollpuffer-Compiler von Google.
Websicheren String decodieren
Da die über das %%EXTRA_TAG_DATA%%
-Makro gesendeten Informationen über eine URL gesendet werden müssen, werden sie von den Google-Servern mit websicherem Base64-Code (RFC 3548) codiert.
Bevor Sie daher eine Entschlüsselung versuchen, müssen Sie die ASCII-Zeichen wieder in einen Bytestring decodieren. Der folgende C++-Beispielcode basiert auf BIO_f_base64() des OpenSSL-Projekts und ist Teil des Beispiel-Entschlüsselungscodes von Google.
string AddPadding(const string& b64_string) { if (b64_string.size() % 4 == 3) { return b64_string + "="; } else if (b64_string.size() % 4 == 2) { return b64_string + "=="; } return b64_string; } // Adapted from http://www.openssl.org/docs/man1.1.0/crypto/BIO_f_base64.html // Takes a web safe base64 encoded string (RFC 3548) and decodes it. // Normally, web safe base64 strings have padding '=' replaced with '.', // but we will not pad the ciphertext. We add padding here because // openssl has trouble with unpadded strings. string B64Decode(const string& encoded) { string padded = AddPadding(encoded); // convert from web safe -> normal base64. int32 index = -1; while ((index = padded.find_first_of('-', index + 1)) != string::npos) { padded[index] = '+'; } index = -1; while ((index = padded.find_first_of('_', index + 1)) != string::npos) { padded[index] = '/'; } // base64 decode using openssl library. const int32 kOutputBufferSize = 256; char output[kOutputBufferSize]; BIO* b64 = BIO_new(BIO_f_base64()); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); BIO* bio = BIO_new_mem_buf(const_cast(padded.data()), padded.length()); bio = BIO_push(b64, bio); int32 out_length = BIO_read(bio, output, kOutputBufferSize); BIO_free_all(bio); return string(output, out_length); }
Struktur eines verschlüsselten Bytestrings
Nachdem Sie die ASCII-Zeichen wieder in einen Bytestring decodiert haben, können Sie ihn entschlüsseln. Der verschlüsselte Bytestring enthält drei Abschnitte:
initialization_vector
: 16 Byte.ciphertext
: Reihe von 20-Byte-Abschnittenintegrity_signature
: 4 Byte.
{initialization_vector (16 bytes)}{ciphertext (20-byte sections)}{integrity_signature (4 bytes)}
Das Byte-Array ciphertext
ist in mehrere 20-Byte-Abschnitte unterteilt, mit der Ausnahme, dass der letzte Abschnitt zwischen 1 und einschließlich 20 Byte enthalten kann. Für jeden Abschnitt der ursprünglichen byte_array
wird der entsprechende 20-Byte-ciphertext
so generiert:
<byte_array <xor> HMAC(encryption_key, initialization_vector || counter_bytes)>
wobei ||
die Verkettung ist.
Definitionen
Variable | Details |
---|---|
initialization_vector |
16 Byte: für die Impression eindeutig. |
encryption_key |
32 Byte werden bei der Kontoeinrichtung angegeben. |
integrity_key |
32 Byte werden bei der Kontoeinrichtung angegeben. |
byte_array |
Ein serialisiertes ExtraTagData -Objekt in 20-Byte-Abschnitten. |
counter_bytes |
Bytewert mit der Ordinalzahl des Abschnitts, siehe unten. |
final_message |
Gesamtbyte-Array, das über das %%EXTRA_TAG_DATA%% -Makro gesendet wurde (ohne WebSafeBase64-Codierung). |
Operatoren | Details |
---|---|
hmac(key, data) |
SHA-1-HMAC, mit key zum Verschlüsseln von data |
a || b |
Der String a ist mit dem String b verkettet. |
Zählerbyte berechnen
counter_bytes
gibt die Reihenfolge der 20-Byte-Abschnitte von ciphertext
an. Der letzte Abschnitt kann zwischen 1 und 20 Byte (einschließlich) enthalten. Um counter_bytes
beim Ausführen der Funktion hmac()
mit dem richtigen Wert zu füllen, zählen Sie die 20-Byte-Abschnitte (einschließlich des Rests) und verwenden Sie die folgende Referenztabelle:
Abschnittsnummer | counter_bytes Wert |
---|---|
0 | Keine |
1 ... 256 | 1 Byte. Der Wert erhöht sich sequenziell von 0 bis 255. |
257 ... 512 | 2 Byte. Der Wert des ersten Bytes ist 0, der Wert des zweiten Bytes erhöht sich sequenziell von 0 auf 255. |
513 ... 768 | 3 Byte. Der Wert der ersten beiden Byte ist 0, der Wert des letzten Byte wird sequenziell von 0 auf 255 erhöht. |
Verschlüsselungsschema
Das Verschlüsselungsschema basiert auf demselben Schema, das auch für die Entschlüsselung des hyperlokalen Targeting-Signals verwendet wird.
Serialisierung: Eine Instanz des ExtraTagData-Objekts, wie im Protokollpuffer definiert, wird zuerst über
SerializeAsString()
zu einem Byte-Array serialisiert.Verschlüsselung: Das Byte-Array wird dann mit einem benutzerdefinierten Verschlüsselungsschema verschlüsselt, um den Größen-Overhead zu minimieren und gleichzeitig eine angemessene Sicherheit zu gewährleisten. Das Verschlüsselungsschema verwendet einen verschlüsselten HMAC-Algorithmus, um ein geheimes Pad basierend auf dem
initialization_vector
zu generieren, das für das Impressionsereignis eindeutig ist.
Pseudocode für Verschlüsselung
byte_array = SerializeAsString(ExtraTagData object) pad = hmac(encryption_key, initialization_vector || counter_bytes ) // for each 20-byte section of byte_array ciphertext = pad <xor> byte_array // for each 20-byte section of byte_array integrity_signature = hmac(integrity_key, byte_array || initialization_vector) // first 4 bytes final_message = initialization_vector || ciphertext || integrity_signature
Entschlüsselungsmethode
Der Entschlüsselungscode muss 1) den Protokollpuffer mit dem Verschlüsselungsschlüssel entschlüsseln und 2) die Integritätsbits mit dem Integritätsschlüssel verifizieren. Die Schlüssel erhalten Sie bei der Kontoeinrichtung. Für die Strukturierung Ihrer Implementierung gibt es keine Einschränkungen. In den meisten Fällen sollten Sie den Beispielcode an Ihre Anforderungen anpassen können.
- Eingabefeld generieren:
HMAC(encryption_key, initialization_vector || counter_bytes)
- XOR: Verwenden Sie dieses Ergebnis und
<xor>
mit dem Geheimtext, um die Verschlüsselung umzukehren. - Überprüfen: Die Integritätssignatur übergibt 4 Byte von
HMAC(integrity_key, byte_array || initialization_vector)
Entschlüsselungs-Pseudocode
// split up according to length rules (initialization_vector, ciphertext, integrity_signature) = final_message // for each 20-byte section of ciphertext pad = hmac(encryption_key, initialization_vector || counter_bytes) // for each 20-byte section of ciphertext byte_array = ciphertext <xor> pad confirmation_signature = hmac(integrity_key, byte_array || initialization_vector) success = (confirmation_signature == integrity_signature)
C++-Beispielcode
Sie enthält eine Schlüsselfunktion aus unserem vollständigen Entschlüsselungsbeispielcode.
bool DecryptByteArray( const string& ciphertext, const string& encryption_key, const string& integrity_key, string* cleartext) { // Step 1. find the length of initialization vector and clear text. const int cleartext_length = ciphertext.size() - kInitializationVectorSize - kSignatureSize; if (cleartext_length < 0) { // The length cannot be correct. return false; } string iv(ciphertext, 0, kInitializationVectorSize); // Step 2. recover clear text cleartext->resize(cleartext_length, '\0'); const char* ciphertext_begin = string_as_array(ciphertext) + iv.size(); const char* const ciphertext_end = ciphertext_begin + cleartext->size(); string::iterator cleartext_begin = cleartext->begin(); bool add_iv_counter_byte = true; while (ciphertext_begin < ciphertext_end) { uint32 pad_size = kHashOutputSize; uchar encryption_pad[kHashOutputSize]; if (!HMAC(EVP_sha1(), string_as_array(encryption_key), encryption_key.length(), (uchar*)string_as_array(iv), iv.size(), encryption_pad, &pad_size)) { printf("Error: encryption HMAC failed.\n"); return false; } for (int i = 0; i < kBlockSize && ciphertext_begin < ciphertext_end; ++i, ++cleartext_begin, ++ciphertext_begin) { *cleartext_begin = *ciphertext_begin ^ encryption_pad[i]; } if (!add_iv_counter_byte) { char& last_byte = *iv.rbegin(); ++last_byte; if (last_byte == '\0') { add_iv_counter_byte = true; } } if (add_iv_counter_byte) { add_iv_counter_byte = false; iv.push_back('\0'); } }
Daten aus dem Werbenetzwerk-Protokollpuffer abrufen
Nachdem Sie die in %%EXTRA_TAG_DATA%%
übergebenen Daten decodiert und entschlüsselt haben, können Sie den Protokollpuffer deserialisieren und die Werbetreibenden-ID für das Targeting abrufen.
Weitere Informationen zu Protokollpuffern finden Sie in unserer Dokumentation.
Definition
Unser Werbenetzwerk-Protokollzwischenspeicher ist wie folgt definiert:
message ExtraTagData { // advertising_id can be Apple's identifier for advertising (IDFA) // or Android's advertising identifier. When the advertising_id is an IDFA, // it is the plaintext returned by iOS's [ASIdentifierManager // advertisingIdentifier]. For hashed_idfa, the plaintext is the MD5 hash of // the IDFA. Only one of the two fields will be available, depending on the // version of the SDK making the request. Later SDKs provide unhashed values. optional bytes advertising_id = 1; optional bytes hashed_idfa = 2; }
Sie müssen ihn mit ParseFromString()
deserialisieren, wie in der C++-Protokollpufferdokumentation beschrieben.
Weitere Informationen zu den Feldern hashed_idfa
für Android und advertising_id
finden Sie unter Werbe-ID entschlüsseln und Targeting auf Inventar in mobilen Apps mit IDFA.
Java-Bibliothek
Anstatt die Kryptoalgorithmen zum Codieren und Decodieren der Werbetreibenden-IDs für Werbenetzwerke zu implementieren, können Sie DoubleClickCrypto.java verwenden. Weitere Informationen finden Sie unter Kryptografie.