เครือข่ายโฆษณาที่ใช้
แท็ก JavaScript ที่ใช้เพื่อเติมโฆษณาผ่าน Authorized Buyers จะมีสิทธิ์
ได้รับตัวระบุผู้ลงโฆษณาสำหรับทั้งอุปกรณ์ Android และ iOS
ข้อมูลนี้ส่งผ่าน %%EXTRA_TAG_DATA%%
หรือ
มาโคร %%ADVERTISING_IDENTIFIER%%
ในแท็ก JavaScript ที่จัดการ
ของ Authorized Buyers เนื้อหาที่เหลือของส่วนนี้มุ่งเน้นที่การดึงข้อมูล
%%EXTRA_TAG_DATA%%
แต่เห็น
รายละเอียดรีมาร์เก็ตติ้งด้วย IDFA หรือรหัสโฆษณา
ในบัฟเฟอร์ Proto ที่เข้ารหัสของ %%ADVERTISING_IDENTIFIER%%
MobileAdvertisingId
ที่สามารถถอดรหัสได้ในที่คล้ายกัน
ไทม์ไลน์
- เครือข่ายโฆษณาอัปเดตแท็กในแอป JavaScript
ผ่าน UI ของ Authorized Buyers
ลงในมาโคร
%%EXTRA_TAG_DATA%%
ตามที่อธิบายไว้ด้านล่าง - ขณะให้บริการ แอปจะขอโฆษณาจาก Authorized Buyers ผ่าน SDK โฆษณาในอุปกรณ์เคลื่อนที่ของ Google ในขณะที่ การส่งตัวระบุผู้ลงโฆษณาอย่างปลอดภัย
- แอปจะได้รับแท็ก JavaScript ที่มี
%%EXTRA_TAG_DATA%%
ที่กรอกด้วยบัฟเฟอร์โปรโตคอลของเครือข่ายโฆษณาที่เข้ารหัสซึ่งมีตัวระบุดังกล่าว - แอปเรียกใช้แท็กนี้ ซึ่งเรียกไปยังเครือข่ายโฆษณาเพื่อชัยชนะ โฆษณาของคุณ
- เพื่อที่จะใช้ (สร้างรายได้) ข้อมูลนี้ เครือข่ายโฆษณาต้องประมวลผล
บัฟเฟอร์โปรโตคอล:
- ถอดรหัสสตริง websafe กลับไปเป็นไบต์สตริงด้วย WebSafeBase64
- ถอดรหัสโดยใช้รูปแบบที่ระบุไว้ด้านล่าง
- ดีซีเรียลไลซ์โปรโตคอลและรับรหัสผู้ลงโฆษณาจาก ExtraTagData.advertising_id หรือ ExtraTagData.hashed_idfa
การอ้างอิง
- WebSafeBase64 โปรแกรมเปลี่ยนไฟล์
- ไลบรารีคริปโตที่รองรับ SHA-1 HMAC เช่น Openssl
- โปรโตคอล Google คอมไพเลอร์บัฟเฟอร์
ถอดรหัสสตริง Websafe
เนื่องจากข้อมูลที่ส่งผ่านมาโคร %%EXTRA_TAG_DATA%%
ต้องส่งผ่าน URL และเซิร์ฟเวอร์ของ Google จะเข้ารหัสด้วย Web-safe base64 (RFC 3548)
ก่อนพยายาม ดังนั้น คุณต้องถอดรหัสอักขระ ASCII กลับไปเป็น ไบต์สตริง โค้ดตัวอย่าง C++ ด้านล่างนี้อิงตาม OpenSSL BIO_f_base64() ของโปรเจ็กต์และเป็นส่วนหนึ่งของตัวอย่างจาก 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<char*>(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); }
โครงสร้างของไบต์สตริงที่เข้ารหัส
เมื่อคุณถอดรหัสอักขระ ASCII กลับไปเป็นไบต์สตริงแล้ว คุณก็พร้อม เพื่อถอดรหัสได้ ไบต์สตริงที่เข้ารหัสมี 3 ส่วนดังนี้
initialization_vector
: 16 ไบต์ciphertext
: ชุดส่วนขนาด 20 ไบต์integrity_signature
: 4 ไบต์
{initialization_vector (16 bytes)}{ciphertext (20-byte sections)}{integrity_signature (4 bytes)}
อาร์เรย์ ciphertext
ไบต์แบ่งออกเป็น 20 ไบต์หลายไบต์
ยกเว้นส่วนสุดท้ายที่อาจมี
รวม 1 และ 20 ไบต์ สำหรับต้นฉบับแต่ละส่วน
byte_array
ซึ่งก็คือ ciphertext
ขนาด 20 ไบต์ที่เกี่ยวข้อง
จะสร้างขึ้นเป็น:
<byte_array <xor> HMAC(encryption_key, initialization_vector || counter_bytes)>
โดยที่ ||
เป็นการต่อกัน
คำจำกัดความ
ตัวแปร | รายละเอียด |
---|---|
initialization_vector |
16 ไบต์ - เฉพาะสำหรับการแสดงผล |
encryption_key |
32 ไบต์ - ระบุไว้เมื่อสร้างบัญชี |
integrity_key |
32 ไบต์ - ระบุไว้เมื่อสร้างบัญชี |
byte_array |
ออบเจ็กต์ ExtraTagData แบบอนุกรมในส่วน 20 ไบต์ |
counter_bytes |
ค่าไบต์ที่แสดงเลขลำดับของส่วน โปรดดูด้านล่าง |
final_message |
ไบต์อาร์เรย์ทั้งหมดที่ส่งผ่านมาโคร %%EXTRA_TAG_DATA%% (ลบการเข้ารหัส WebSafeBase64) |
โอเปอเรเตอร์ | รายละเอียด |
---|---|
hmac(key, data) |
SHA-1 HMAC โดยใช้ key เพื่อเข้ารหัส data |
a || b |
สตริง a ที่เชื่อมต่อกับสตริง b |
คำนวณไบต์ของตัวนับ
counter_bytes
ทำเครื่องหมายลำดับของส่วนขนาด 20 ไบต์แต่ละส่วนของ
ciphertext
โปรดทราบว่าส่วนสุดท้ายอาจมีค่าระหว่าง 1 ถึง
รวม 20 ไบต์ เพื่อกรอก counter_bytes
ด้วยค่าที่ถูกต้อง
เมื่อเรียกใช้ฟังก์ชัน hmac()
ให้นับส่วน 20 ไบต์
(รวมส่วนที่เหลือ) และใช้ตารางอ้างอิงต่อไปนี้
หมายเลขส่วน | ค่า counter_bytes |
---|---|
0 | ไม่มี |
1 ... 256 ตัว | 1 ไบต์ โดยค่าจะเพิ่มขึ้นจาก 0 ถึง 255 ตามลำดับ |
257 ... 512 | 2 ไบต์ ค่าของไบต์แรกคือ 0 ค่าของไบต์ที่สอง เพิ่มขึ้นจาก 0 ถึง 255 ตามลำดับ |
513 ... 768 | 3 ไบต์ ค่าของสองไบต์แรกคือ 0 ซึ่งเป็นค่าของไบต์สุดท้าย เพิ่มขึ้นจาก 0 ถึง 255 ตามลำดับ |
รูปแบบการเข้ารหัส
รูปแบบการเข้ารหัสจะขึ้นอยู่กับรูปแบบเดียวกับที่ใช้สำหรับการถอดรหัส สัญญาณการกำหนดเป้าหมายแบบเจาะจงพื้นที่
การทำให้เป็นอนุกรม: อินสแตนซ์ของออบเจ็กต์ ExtraTagData เป็น ที่กำหนดไว้ในบัฟเฟอร์โปรโตคอลจะได้รับการทำอนุกรมผ่าน
SerializeAsString()
เป็นอาร์เรย์ไบต์การเข้ารหัส: จากนั้นจะเข้ารหัสอาร์เรย์แบบไบต์โดยใช้ รูปแบบการเข้ารหัสที่กำหนดเอง ซึ่งออกแบบมาเพื่อลดโอเวอร์เฮดของขนาด พร้อมทำให้มั่นใจได้ว่า การรักษาความปลอดภัยที่เพียงพอ รูปแบบการเข้ารหัสใช้อัลกอริทึม HMAC ที่คีย์เพื่อสร้าง สมุดปิดลับจาก
initialization_vector
ซึ่งเป็นเอกลักษณ์ของ เหตุการณ์การแสดงผล
ซูโดโค้ดการเข้ารหัส
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
รูปแบบการถอดรหัส
โค้ดถอดรหัสต้อง 1) ถอดรหัสบัฟเฟอร์โปรโตคอลโดยใช้การเข้ารหัส และ 2) ตรวจสอบบิตแสดงความสมบูรณ์ของข้อมูลด้วยคีย์ความสมบูรณ์ คีย์ต่างๆ จะ ที่ได้รับจากคุณในระหว่างการสร้างบัญชี ไม่มีข้อจำกัดใดๆ เกี่ยวกับวิธีที่คุณ จัดโครงสร้างการติดตั้งใช้งาน โดยส่วนใหญ่แล้ว คุณควรจะสามารถติดต่อกับ โค้ดตัวอย่างและปรับเปลี่ยนได้ตามความต้องการ
- สร้างแพด:
HMAC(encryption_key, initialization_vector || counter_bytes)
- XOR: นำผลลัพธ์นี้ไปและ
<xor>
ที่มี ข้อความเข้ารหัสเพื่อย้อนกลับการเข้ารหัส - ยืนยัน: ลายเซ็นความสมบูรณ์ส่งข้อมูล 4 ไบต์ของ
HMAC(integrity_key, byte_array || initialization_vector)
ซูโดโค้ดการถอดรหัส
// 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++
ในที่นี้คือฟังก์ชันหลักจากชุดเครื่องมือ การถอดรหัส โค้ดตัวอย่าง
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'); } }
รับข้อมูลจากบัฟเฟอร์โปรโตคอลของเครือข่ายโฆษณา
เมื่อคุณถอดรหัสและถอดรหัสข้อมูลที่ส่งไป
%%EXTRA_TAG_DATA%%
คุณพร้อมทำการดีซีเรียลบัฟเฟอร์โปรโตคอลแล้ว
และรับตัวระบุผู้ลงโฆษณาสำหรับการกำหนดเป้าหมาย
หากคุณไม่คุ้นเคยกับบัฟเฟอร์โปรโตคอล ให้เริ่มอ่านเอกสารประกอบ
คำจำกัดความ
บัฟเฟอร์โปรโตคอลเครือข่ายโฆษณาของเรามีคำจำกัดความดังนี้
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; }
คุณจะต้องดีซีเรียลไลซ์โดยใช้ ParseFromString()
ตามที่อธิบายไว้ใน
เอกสารประกอบเกี่ยวกับบัฟเฟอร์โปรโตคอล C++
ดูรายละเอียดเกี่ยวกับ Android advertising_id
และ iOS
ฟิลด์ hashed_idfa
โปรดดูการถอดรหัส
รหัสโฆษณาและการกำหนดเป้าหมายแอปบนอุปกรณ์เคลื่อนที่
พื้นที่โฆษณาที่มี IDFA
ไลบรารี Java
แทนที่จะใช้อัลกอริทึมคริปโตในการเข้ารหัสและถอดรหัส ตัวระบุผู้ลงโฆษณาสำหรับเครือข่ายโฆษณา DoubleClickCrypto.java. สำหรับข้อมูลเพิ่มเติม โปรดดู วิทยาการเข้ารหัสลับ