การถอดรหัสตัวระบุผู้ลงโฆษณาสำหรับเครือข่ายโฆษณา

เครือข่ายโฆษณาที่ใช้ แท็ก JavaScript ที่ใช้เพื่อเติมโฆษณาผ่าน Authorized Buyers จะมีสิทธิ์ ได้รับตัวระบุผู้ลงโฆษณาสำหรับทั้งอุปกรณ์ Android และ iOS ข้อมูลนี้ส่งผ่าน %%EXTRA_TAG_DATA%% หรือ มาโคร %%ADVERTISING_IDENTIFIER%% ในแท็ก JavaScript ที่จัดการ ของ Authorized Buyers เนื้อหาที่เหลือของส่วนนี้มุ่งเน้นที่การดึงข้อมูล %%EXTRA_TAG_DATA%% แต่เห็น รายละเอียดรีมาร์เก็ตติ้งด้วย IDFA หรือรหัสโฆษณา ในบัฟเฟอร์ Proto ที่เข้ารหัสของ %%ADVERTISING_IDENTIFIER%% MobileAdvertisingId ที่สามารถถอดรหัสได้ในที่คล้ายกัน

ไทม์ไลน์

  1. เครือข่ายโฆษณาอัปเดตแท็กในแอป JavaScript ผ่าน UI ของ Authorized Buyers ลงในมาโคร %%EXTRA_TAG_DATA%% ตามที่อธิบายไว้ด้านล่าง
  2. ขณะให้บริการ แอปจะขอโฆษณาจาก Authorized Buyers ผ่าน SDK โฆษณาในอุปกรณ์เคลื่อนที่ของ Google ในขณะที่ การส่งตัวระบุผู้ลงโฆษณาอย่างปลอดภัย
  3. แอปจะได้รับแท็ก JavaScript ที่มี %%EXTRA_TAG_DATA%% ที่กรอกด้วยบัฟเฟอร์โปรโตคอลของเครือข่ายโฆษณาที่เข้ารหัสซึ่งมีตัวระบุดังกล่าว
  4. แอปเรียกใช้แท็กนี้ ซึ่งเรียกไปยังเครือข่ายโฆษณาเพื่อชัยชนะ โฆษณาของคุณ
  5. เพื่อที่จะใช้ (สร้างรายได้) ข้อมูลนี้ เครือข่ายโฆษณาต้องประมวลผล บัฟเฟอร์โปรโตคอล:
    1. ถอดรหัสสตริง websafe กลับไปเป็นไบต์สตริงด้วย WebSafeBase64
    2. ถอดรหัสโดยใช้รูปแบบที่ระบุไว้ด้านล่าง
    3. ดีซีเรียลไลซ์โปรโตคอลและรับรหัสผู้ลงโฆษณาจาก ExtraTagData.advertising_id หรือ ExtraTagData.hashed_idfa

การอ้างอิง

  1. WebSafeBase64 โปรแกรมเปลี่ยนไฟล์
  2. ไลบรารีคริปโตที่รองรับ SHA-1 HMAC เช่น Openssl
  3. โปรโตคอล 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 ตามลำดับ

กลับไปด้านบน

รูปแบบการเข้ารหัส

รูปแบบการเข้ารหัสจะขึ้นอยู่กับรูปแบบเดียวกับที่ใช้สำหรับการถอดรหัส สัญญาณการกำหนดเป้าหมายแบบเจาะจงพื้นที่

  1. การทำให้เป็นอนุกรม: อินสแตนซ์ของออบเจ็กต์ ExtraTagData เป็น ที่กำหนดไว้ในบัฟเฟอร์โปรโตคอลจะได้รับการทำอนุกรมผ่าน SerializeAsString() เป็นอาร์เรย์ไบต์

  2. การเข้ารหัส: จากนั้นจะเข้ารหัสอาร์เรย์แบบไบต์โดยใช้ รูปแบบการเข้ารหัสที่กำหนดเอง ซึ่งออกแบบมาเพื่อลดโอเวอร์เฮดของขนาด พร้อมทำให้มั่นใจได้ว่า การรักษาความปลอดภัยที่เพียงพอ รูปแบบการเข้ารหัสใช้อัลกอริทึม 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) ตรวจสอบบิตแสดงความสมบูรณ์ของข้อมูลด้วยคีย์ความสมบูรณ์ คีย์ต่างๆ จะ ที่ได้รับจากคุณในระหว่างการสร้างบัญชี ไม่มีข้อจำกัดใดๆ เกี่ยวกับวิธีที่คุณ จัดโครงสร้างการติดตั้งใช้งาน โดยส่วนใหญ่แล้ว คุณควรจะสามารถติดต่อกับ โค้ดตัวอย่างและปรับเปลี่ยนได้ตามความต้องการ

  1. สร้างแพด: HMAC(encryption_key, initialization_vector || counter_bytes)
  2. XOR: นำผลลัพธ์นี้ไปและ <xor> ที่มี ข้อความเข้ารหัสเพื่อย้อนกลับการเข้ารหัส
  3. ยืนยัน: ลายเซ็นความสมบูรณ์ส่งข้อมูล 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. สำหรับข้อมูลเพิ่มเติม โปรดดู วิทยาการเข้ารหัสลับ