เครือข่ายโฆษณาที่ใช้
แท็ก 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. สำหรับข้อมูลเพิ่มเติม โปรดดู วิทยาการเข้ารหัสลับ