เครือข่ายโฆษณาที่ใช้
แท็ก JavaScript เพื่อเติมโฆษณาผ่าน Authorized Buyers จะมีสิทธิ์ได้รับตัวระบุผู้ลงโฆษณาสำหรับทั้งอุปกรณ์ Android และ iOS
ข้อมูลจะส่งผ่านทางมาโคร %%EXTRA_TAG_DATA%%
หรือ %%ADVERTISING_IDENTIFIER%%
ในแท็ก JavaScript ที่จัดการโดย Authorized Buyers เนื้อหาที่เหลือของส่วนนี้เน้นที่การแยก
%%EXTRA_TAG_DATA%%
แต่ดู
รีมาร์เก็ตติ้งที่มี IDFA หรือรหัสโฆษณาเพื่อดูรายละเอียดเกี่ยวกับ%%ADVERTISING_IDENTIFIER%%
บัฟเฟอร์ Proto ที่เข้ารหัส
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++ ด้านล่างอิงจาก BIO_f_base64() ของโปรเจ็กต์ OpenSSL และเป็นส่วนหนึ่งของตัวอย่างโค้ดการถอดรหัสของ 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); }
โครงสร้างของไบต์สตริงที่เข้ารหัส
เมื่อคุณถอดรหัสอักขระ 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 ค่าของไบต์ที่ 2 จะเพิ่มขึ้นจาก 0 ถึง 255 ตามลำดับ |
513 ... 768 | 3 ไบต์ ค่าของ 2 ไบต์แรกคือ 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)
การถอดรหัส 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++
นี่คือฟังก์ชันหลักจากตัวอย่างโค้ดการถอดรหัสที่สมบูรณ์ของเรา
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 แทนการใช้อัลกอริทึมคริปโตในการเข้ารหัสและถอดรหัสตัวระบุผู้ลงโฆษณาสำหรับเครือข่ายโฆษณา ดูข้อมูลเพิ่มเติมได้ที่วิทยาการเข้ารหัสลับ