DSP จัดการกับโพสต์แบ็ก SKAdNetwork อย่างไร? แพลตฟอร์มฝั่งอุปสงค์ (DSP) และเครือข่ายโฆษณาจัดการกับโพสต์แบ็ก SKAdNetwork โดยการตั้งค่าจุดสิ้นสุดการรับข้อมูล HTTP POST ที่ปลอดภัย สร้างสตริงข้อความ UTF-8 ที่จัดเรียงแล้วโดยใช้ตัวคั่น U+2063 ตรวจสอบลายเซ็นเข้ารหัส ECDSA P-256 ของ Apple เทียบกับกุญแจสาธารณะที่ Apple เผยแพร่ และบันทึกรหัสธุรกรรมที่ตรวจสอบแล้วเพื่อป้องกันการประมวลผลซ้ำก่อนที่จะอัปเดตโมเดลการประมูล
โพสต์แบ็กยืนยันการติดตั้งของ SKAdNetwork คือการแจ้งเตือน HTTPS POST ที่ลงนามโดย Apple ซึ่งระบบปฏิบัติการจะส่งไปยังเครือข่ายโฆษณาที่มีสิทธิ์ และสำหรับกรณีที่การระบุแหล่งที่มาสำเร็จ (winning attributions) จะส่งไปยังจุดสิ้นสุดสำเนาที่กำหนดค่าไว้ของผู้พัฒนาแอปพลิเคชันที่ลงโฆษณาด้วย เพื่อความสมบูรณ์ของข้อมูล ระบบรับข้อมูลแบ็กเอนด์จะต้องตรวจสอบลายเซ็น ECDSA P-256 ของ Apple ตรวจความถูกต้องของการจัดเรียงพารามิเตอร์ และบังคับใช้การขจัดข้อมูลซ้ำในระดับธุรกรรม
| คำศัพท์ | คำนิยาม |
|---|---|
| SKAdNetwork | เฟรมเวิร์กในระดับแพลตฟอร์มของ Apple สำหรับการระบุแหล่งที่มาแคมเปญโฆษณาที่รักษาความเป็นส่วนตัว |
| Install-Validation Postback | เพย์โหลด JSON ที่ลงนามโดย Apple ซึ่งประกอบด้วยข้อมูลเมตาดาต้าการยืนยันการติดตั้งและการระบุแหล่งที่มาหลังจากการแปลงโฆษณาที่ผ่านเกณฑ์ |
| ECDSA P-256 | อัลกอริทึมการเข้ารหัสลับแบบเส้นโค้งวงรีที่ Apple ใช้เพื่อลงนามโพสต์แบ็กยืนยันการติดตั้ง |
| Transaction ID | ตัวระบุการตรวจสอบที่ไม่ซ้ำกัน ซึ่งระบบปลายทางใช้เป็นคีย์ความสมมูล (idempotency key) สำหรับการตรวจจับข้อมูลที่ซ้ำกัน |
สถาปัตยกรรมการรับโพสต์แบ็ก SKAdNetwork สำหรับ DSP และเครือข่ายโฆษณา
ท่อส่งข้อมูลการรับสองทาง: การส่งตรงไปยังเครือข่ายโฆษณาเทียบกับจุดสิ้นสุดโพสต์แบ็กของผู้พัฒนา
เมื่อมีการติดตั้งแอปพลิเคชัน iOS ที่มีการระบุแหล่งที่มาเกิดขึ้น ระบบย่อยการระบุแหล่งที่มาของ Apple จะส่งโพสต์แบ็กยืนยันการติดตั้งผ่าน HTTPS POST:
- การรับข้อมูลของเครือข่ายโฆษณา: อุปกรณ์จะส่งโพสต์แบ็กหลักที่ชนะ (
did-win: true) ไปยัง URL ของเซิร์ฟเวอร์ที่ลงทะเบียนภายใต้ad-network-idที่สอดคล้องกันในรีจิสทรีของ Apple โดยตรง - การรับข้อมูลสำเนาของผู้พัฒนา: หากแอปพลิเคชันที่ลงโฆษณาระบุคีย์
NSAdvertisingAttributionReportEndpointไว้ในไฟล์Info.plistอุปกรณ์จะส่งสำเนาที่ตรงกันทุกประการของโพสต์แบ็กที่ชนะไปยังเซิร์ฟเวอร์ของผู้พัฒนาพร้อมกันด้วย - การส่งเส้นทางโพสต์แบ็กที่ไม่ชนะ: เริ่มตั้งแต่ SKAdNetwork 3.0 หากมีหลายเครือข่ายโฆษณาที่มีคุณสมบัติผ่านเกณฑ์การระบุแหล่งที่มาแต่ไม่ชนะ อุปกรณ์จะส่งโพสต์แบ็กที่ไม่ชนะสูงสุดถึงห้ารายการ (
did-win: false) ไปยังเครือข่ายโฆษณาสำรองที่มีคุณสมบัติเหล่านั้นโดยตรง โดยโพสต์แบ็กที่ไม่ชนะจะไม่ถูกส่งไปยังจุดสิ้นสุดสำเนาของผู้พัฒนา
จุดสิ้นสุดการรับข้อมูลแบ็กเอนด์ควรตอบกลับด้วย HTTP 200 OK หากอุปกรณ์ไม่ได้รับ 200 กลับมา อุปกรณ์อาจลองส่งใหม่อีกครั้งสูงสุดถึงเก้าครั้งภายในระยะเวลาสูงสุดเก้าวัน

บทบาทของ NSAdvertisingAttributionReportEndpoint ในการตรวจสอบของผู้พัฒนา
NSAdvertisingAttributionReportEndpoint ช่วยให้ผู้พัฒนาแอปสามารถรับสำเนาโพสต์แบ็กที่ชนะได้โดยตรง โดยไม่ต้องพึ่งพาการส่งต่อจากเครือข่ายโฆษณา:
- การตรวจสอบอิสระ: ผู้พัฒนาจะได้รับสำเนาที่แน่นอนของโพสต์แบ็กที่ชนะทั้งหมดที่สร้างขึ้นสำหรับแอปพลิเคชันของตน ซึ่งช่วยให้สามารถตรวจสอบรายงานของเครือข่ายโฆษณาภายในได้
- เส้นทางจุดสิ้นสุดเฉพาะ: เซิร์ฟเวอร์ของผู้พัฒนาต้องโฮสต์จุดสิ้นสุดที่
https://<domain>/.well-known/skadnetwork/report-attribution/ - ความแตกต่างของ AdAttributionKit: สำหรับ AdAttributionKit ทาง Apple ได้กำหนดค่าเส้นทางแยกต่างหากไปยัง
https://<domain>/.well-known/appattribution/report-attribution/ซึ่งใช้สถาปัตยกรรมการตรวจสอบความถูกต้องแบบ JSON Web Signature (JWS)
วิธีที่ MMP รับ รวบรวม และปรับมาตรฐานสตรีมเหตุการณ์ S2S จากหลายเครือข่าย
ขึ้นอยู่กับการบูรกราการทางธุรกิจ พันธมิตรการวัดผลมือถือ (MMP) อาจรับข้อมูล SKAdNetwork ผ่านการส่งต่อฝั่งผู้พัฒนา การบูรณาการกับเครือข่ายโฆษณา หรือโฟลว์เซิร์ฟเวอร์พาร์ทเนอร์ที่กำหนดเอง:
- การรับข้อมูลจากหลายแหล่ง: การรับข้อมูลโพสต์แบ็กที่ตรวจสอบแล้วซึ่งส่งต่อมาจากจุดสิ้นสุดของผู้พัฒนาควบคู่ไปกับสตรีมรายงานจากเครือข่ายโฆษณาโดยตรง
- การขขจัดความซ้ำซ้อนข้ามสตรีม: การปรับมาตรฐานและขจัดข้อมูลที่ซ้ำกันโดยใช้
transaction-idที่ไม่ซ้ำกันข้ามสำเนาที่แชร์ระหว่างเครือข่ายโฆษณาและผู้พัฒนา - การปรับมาตรฐาน BI ปลายทาง: การแมปค่าการแปลงแบบหยาบและแบบละเอียดเข้ากับโมเดลรายได้และเหตุการณ์ในฟวยด์ที่กำหนดโดยลูกค้า
ดูเพิ่มเติม: SKAdNetwork ──> โมเดลการระบุแหล่งที่มาบนมือถือ
การตรวจสอบด้วยการเข้ารหัส: การตรวจสอบลายเซ็น ECDSA P-256 ของ Apple
ทำความเข้าใจสแต็กการเข้ารหัส: NIST Curve P-256 (secp256r1) ร่วมกับ SHA-256
โพสต์แบ็ก SKAdNetwork ทุกรายการจะมีฟิลด์ attribution-signature ลายเซ็นเข้ารหัสนี้สร้างขึ้นโดย Apple โดยใช้อัลกอริทึมลายเซ็นดิจิทัลเส้นโค้งวงรี (ECDSA) กับเคิร์ฟ NIST P-256 (secp256r1) และใช้ไดเจสต์ SHA-256
ลายเซ็นนี้จะตรวจสอบคุณสมบัติด้านความปลอดภัยพื้นฐานสองประการ:
- ความแท้จริง (Authenticity): โพสต์แบ็กถูกสร้างขึ้นโดยตรงจากระบบย่อยแพลตฟอร์มของ Apple บนอุปกรณ์ที่ได้รับการตรวจสอบแล้ว ไม่ได้ถูกปลอมแปลงโดยไคลเอนต์หรือพร็อกซีที่ไม่ประสงค์ดี
- ความสมบูรณ์ของข้อมูล (Integrity): พารามิเตอร์ที่ครอบคลุมโดยลายเซ็นนั้นไม่ถูกแก้ไขระหว่างการส่งผ่านข้อมูล
การใช้กุญแจสาธารณะ SKAdNetwork ที่ Apple เผยแพร่
ในการตรวจสอบลายเซ็น เซิร์ฟเวอร์รับข้อมูลจะต้องโหลดกุญแจสาธารณะอย่างเป็นทางการของ Apple สำหรับ SKAdNetwork 2.1 และใหม่กว่า Apple จะเผยแพร่กุญแจสาธารณะ NIST P-256 โดยเฉพาะไว้ในเอกสารประกอบสำหรับนักพัฒนา:
- การเริ่มต้นใช้งานกุญแจ: กุญแจสาธารณะจะถูกโหลดลงในหน่วยความจำในฐานะวัตถุกุญแจสาธารณะ X.509/DER มาตรฐานในระหว่างการเริ่มต้นเซิร์ฟเวอร์
- การตรวจสอบลายเซ็นอสมมาตร: เอ็นจิ้นการตรวจสอบจะสร้างสตริงข้อความที่จัดเรียงรูปแบบ UTF-8 ขึ้นมาใหม่ คำนวณแฮช SHA-256 และตรวจสอบ
attribution-signatureที่ถอดรหัส Base64 แล้วเทียบกับข้อความที่สร้างขึ้นใหม่
[Device / Subsystem] ──► [Dispatches Signed JSON Postback]
│
▼
[DSP / Ad Network Ingestion Endpoint]
(HTTPS POST to registered postback URL)
│
▼
[Parse JSON & Reconstruct Message String]
(Concatenate UTF-8 fields with \u2063)
│
▼
[ECDSA P-256 Public Key Signature Verification]
│
┌──────────────┴──────────────┐
▼ ▼
[Signature Valid] [Signature Invalid]
│ │
▼ ▼
[Atomic Deduplication] [Log Error & Discard]
(Check transaction-id)
│
▼
[Process Attribution]

เหตุใดการใช้แฮชเพียงอย่างเดียวจึงไม่เพียงพอ: การตรวจสอบลายเซ็นแบบอสมมาตร
เนื่องจาก Apple ลงนามเพย์โหลดด้วยคีย์ส่วนตัว (private key) และไม่มีการแจกจ่ายคีย์ลับร่วมกัน จึงไม่สามารถใช้การตรวจสอบแบบสมมาตร (เช่น HMAC-SHA256) ได้ เอ็นจิ้นการรับข้อมูลจึงต้องใช้งานการตรวจสอบลายเซ็นด้วยกุญแจสาธารณะแบบอสมมาตรมาตรฐานผ่านไลบรารีการเข้ารหัสลับมาตรฐาน (เช่น OpenSSL, crypto ของ Node.js หรือ cryptography ของ Python)
การสร้างสตริงข้อความสำหรับการตรวจสอบลายเซ็น
โปรโตคอลการจัดเรียงรูปแบบที่เข้มงวด: บทบาทของตัวคั่นที่มองไม่เห็น (\u2063)
Apple กำหนดรูปแบบการจัดเรียงไบต์ UTF-8 ที่แน่นอนเพื่อสร้างสตริงข้อความสำหรับการตรวจสอบลายเซ็น พารามิเตอร์จะต้องถูกนำมาต่อกันตามลำดับที่แม่นยำ โดยคั่นด้วยอักขระ Unicode ที่มองไม่เห็น \u2063 (U+2063 Invisible Separator, ชุดไบต์ UTF-8 0xE2 0x81 0xA3):
การแทนที่ด้วยช่องว่าง เครื่องหมายวรรคตอนมาตรฐาน หรือตัวคั่น Unicode ทางเลือกอื่น จะทำให้การตรวจสอบความถูกต้องด้วยการเข้ารหัสล้มเหลว
ลำดับพารามิเตอร์เฉพาะเวอร์ชันสำหรับ SKAN 4.0
อ้างอิงจาก เอกสารประกอบสำหรับนักพัฒนาของ Apple เกี่ยวกับการตรวจสอบโพสต์แบ็กยืนยันการติดตั้ง พารามิเตอร์สำหรับโพสต์แบ็ก SKAdNetwork 4.0 จะต้องถูกจัดเรียงตามลำดับที่แน่นอนดังต่อไปนี้:
version(เช่น"4.0")ad-network-id(เช่น"example123.skadnetwork")source-identifier(เช่น"4821")app-id(เช่น1234567890)transaction-id(เช่น"6a8b1c2d-3e4f-5a6b-7c8d-9e0f1a2b3c4d")redownload(เช่น"true"หรือ"false"ในรูปแบบสตริงตัวพิมพ์เล็ก)source-app-id(สำหรับโฆษณาแบบแอปพลิเคชันสู่แอปพลิเคชัน) หรือsource-domain(สำหรับโฆษณาแบบเว็บสู่แอปพลิเคชันใน Safari) ซึ่งรวมไว้เฉพาะเมื่อมีอยู่ในโพสต์แบ็กเท่านั้นfidelity-type(เช่น1สำหรับโฆษณาที่เรนเดอร์โดย StoreKit หรือโฆษณาบนเว็บที่ระบุแหล่งที่มาโดย SKAdNetwork;0สำหรับโฆษณาแบบมองเห็นโดยไม่ต้องคลิก)did-win(เช่น"true"หรือ"false"ในรูปแบบสตริงตัวพิมพ์เล็ก)postback-sequence-index(เช่น0,1หรือ2)
ข้อกำหนดสำคัญของ SKAN 4: ค่าการแปลงถูกยกเว้นจากการลงนามลายเซ็น
ใน SKAdNetwork 4.0 ลายเซ็นของ Apple ไม่รวมถึง conversion-value หรือ coarse-conversion-value แม้ว่าฟิลด์ใดฟิลด์หนึ่งเหล่านี้จะปรากฏอยู่ในเพย์โหลด JSON ก็ตาม สตริงที่จัดเรียงสำหรับ SKAN 4 จะสิ้นสุดที่ postback-sequence-index การพยายามผนวกค่าการแปลงเข้ากับสตริงข้อความจะทำให้การตรวจสอบล้มเหลว
เพย์โหลด JSON ด้านล่างแสดงโครงสร้างโพสต์แบ็ก SKAdNetwork 4.0 ที่สมบูรณ์ ลายเซ็นด้านล่างนี้เป็นตัวอย่างจำลองและจะไม่ผ่านการตรวจสอบด้วยการเข้ารหัส สำหรับการทดสอบยูนิตเทสต์ ให้ใช้ตัวอย่างที่ลงนามแล้วของ Apple จากเอกสารประกอบการตรวจสอบอย่างเป็นทางการ:
{
"version": "4.0",
"ad-network-id": "example123.skadnetwork",
"source-identifier": "4821",
"app-id": 1234567890,
"transaction-id": "6a8b1c2d-3e4f-5a6b-7c8d-9e0f1a2b3c4d",
"redownload": false,
"source-app-id": 9876543210,
"fidelity-type": 1,
"did-win": true,
"postback-sequence-index": 0,
"conversion-value": 47,
"attribution-signature": "MEQCIFz8...SAMPLE_CRYPTOGRAPHIC_SIGNATURE...=="
}
การจัดการเพย์โหลด SKAN 4.0 แบบหลายหน้าต่างเวลาและจุดสิ้นสุดของผู้พัฒนา
การแยกวิเคราะห์ postback-sequence-index ข้ามหน้าต่างเวลาการแปลงแบบลำดับ
ใน SKAdNetwork 4.0 การแปลงจะสร้างโพสต์แบ็กจากหน้าต่างเวลาการแปลงที่ครอบคลุมนานสูงสุด 35 วันหลังจากการเปิดใช้งานแอปครั้งแรก โดยการส่งมอบจริงจะเกิดขึ้นหลังจากความล่าชหลังสิ้นสุดหน้าต่างเวลาที่สุ่มโดย Apple ระบบรับข้อมูลแบ็กเอนด์จะแยกวิเคราะห์ฟิลด์ postback-sequence-index เพื่อกำหนดข้อมูลการแปลงไปยังหน้าต่างวงจรชีวิตที่ถูกต้อง:
- ดัชนี
0(หน้าต่างที่ 1: วันที่ 0–2): ประกอบด้วยค่าการแปลงแบบละเอียด (0–63) หรือค่าการแปลงแบบหยาบ (low,medium,high) หรือฟิลด์อาจไม่มีอยู่ - ดัชนี
1(หน้าต่างที่ 2: วันที่ 3–7): สำหรับระดับข้อมูลโพสต์แบ็ก 1–3 อาจมีการเปิดเผยcoarse-conversion-value(low,medium,high) เมื่อมีข้อมูล; ระดับ 0 ไม่มีสิทธิ์ได้รับโพสต์แบ็กครั้งที่สองหรือสาม - ดัชนี
2(หน้าต่างที่ 3: วันที่ 8–35): สำหรับระดับข้อมูลโพสต์แบ็ก 1–3 อาจมีการเปิดเผยcoarse-conversion-value(low,medium,high) เมื่อมีข้อมูล; ระดับ 0 ไม่มีสิทธิ์ได้รับโพสต์แบ็กครั้งที่สองหรือสาม
การจัดการค่าการแปลงแบบละเอียดเทียบกับแบบหยาบ
ตัวถอดรหัสการรับข้อมูลจะต้องคำนึงถึงความแปรปรวนของเพย์โหลด:
- ความไม่เข้ากันร่วมกัน (Mutual Exclusivity): Apple กำหนดว่าโพสต์แบ็กยืนยันการติดตั้งอาจมี
conversion-valueหรือcoarse-conversion-valueอย่างใดอย่างหนึ่ง แต่จะไม่มีทั้งสองค่าพร้อมกัน - การไม่มีค่าการแปลง: หากระดับข้อมูลโพสต์แบ็กที่กำหนดอยู่ในระดับต่ำ (ระดับ 0) ฟิลด์ค่าการแปลงจะถูกละเว้นจากเพย์โหลด JSON
การป้องกันการโจมตีแบบ Replay Attack และเพย์โหลดการแปลงที่ถูกปลอมแปลง
บทบาทของ transaction-id ในฐานะคีย์สำหรับการขจัดข้อมูลซ้ำ
โพสต์แบ็ก SKAdNetwork ทุกรายการจะมี UUID ของ transaction-id ที่ไม่ซ้ำกัน เอกสารของ Apple แนะนำให้ผู้รับใช้ตัวระบุนี้เป็นคีย์ความสมมูล (idempotency key) เพื่อตรวจจับและทิ้งโพสต์แบ็กการแปลงที่ซ้ำกัน
เนื่องจากตัวรับโพสต์แบ็กเป็นจุดสิ้นสุด HTTPS ที่เข้าถึงได้แบบสาธารณะ ผู้ไม่ประสงค์ดีจึงอาจพยายามโจมตีด้วยการเล่นซ้ำ (replay attack) โดยการดักจับโพสต์แบ็กที่ถูกต้องและส่งซ้ำหลายๆ ครั้งเพื่อเพิ่มตัวชี้วัดการแปลงอย่างไม่ถูกต้อง
การใช้งานแคชในหน่วยความจำแบบกระจายและบันทึกข้อมูลถาวร
Apple ไม่ได้กำหนดระยะเวลาการเก็บรักษาสำหรับการขจัดข้อมูลซ้ำที่เป็นสากล ผู้รับในระบบจริงควรเก็บบันทึกความสมมูลที่มีความคงทนสำหรับรหัสธุรกรรมที่ตรวจสอบแล้ว ตามข้อกำหนดในการรวบรวมบัญชีและการป้องกันการเล่นซ้ำของตน โดยอาจใช้ Redis TTL เป็นการเพิ่มประสิทธิภาพแคชแบบร้อน (hot-cache) แทนที่จะเป็นบันทึกข้อมูลซ้ำที่เชื่อถือได้เพียงแห่งเดียว:
- ตรวจสอบลายเซ็นด้วยการเข้ารหัสก่อน: ตรวจสอบลายเซ็น ECDSA กับกุญแจสาธารณะของ Apple ให้สมบูรณ์ก่อนที่จะบันทึกรหัสธุรกรรมลงในพื้นที่จัดเก็บ
- การขจัดข้อมูลซ้ำแบบอะตอมิก (Atomic Deduplication): ดำเนินการเขียนแบบอะตอมิก (เช่น คำสั่ง Redis
SET key value NX EX <seconds>) ที่สนับสนุนด้วยข้อจำกัดความไม่ซ้ำกันของฐานข้อมูลความสัมพันธ์หรือฐานข้อมูลเอกสารแบบถาวร - ขอบเขตการขจัดข้อมูลซ้ำ: กำหนดหน้าต่างเวลาการเก็บรักษาในการทำงานในชั้นแคชที่ครอบคลุมถึงการส่งมอบโพสต์แบ็กที่คาดไว้ การลองส่งซ้ำของเครือข่าย (Apple จะลองส่งซ้ำสำหรับการส่งมอบที่ล้มเหลวเป็นเวลาสูงสุด 9 วัน) และการกระทบยอดข้อมูลในขั้นตอนต่อไป

การใช้งานแบ็กเอนด์ด้านล่างแสดงตัวอย่างการตรวจสอบความถูกต้องของลายเซ็น การตรวจสอบสคีมา และการขจัดข้อมูลซ้ำแบบอะตอมิกใน Python:
import base64
import json
import redis
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.serialization import load_der_public_key
from cryptography.exceptions import InvalidSignature
# Initialize Redis client for hot-cache transaction deduplication
redis_client = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
# Official Apple SKAdNetwork 2.1+ Public Key (Base64 DER encoded, published by Apple)
APPLE_SKAN_PUBLIC_KEY_B64 = (
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWdp8GPcGqmhgzEFj9Z2nSpQVdday"
"aPe4FMzqM9wib1+aHaaIzoHoLN9zW4K8y4SPykE3YVK3sVqW6Af0lfx3gg=="
)
# Exact Apple-specified invisible separator: U+2063 INVISIBLE SEPARATOR (UTF-8: 0xE2 0x81 0xA3)
SEPARATOR = "\u2063"
def construct_skan4_message_bytes(payload: dict) -> bytes:
"""
Constructs the serialized UTF-8 message string for SKAN 4.0 signature verification.
Apple specification explicitly EXCLUDES conversion-value and coarse-conversion-value from the signature.
"""
parts = [
str(payload["version"]),
str(payload["ad-network-id"]),
str(payload["source-identifier"]),
str(payload["app-id"]),
str(payload["transaction-id"]),
"true" if payload["redownload"] is True else "false"
]
# Include source-app-id (app ad) OR source-domain (web ad) if present
if payload.get("source-app-id") is not None:
parts.append(str(payload["source-app-id"]))
elif payload.get("source-domain") is not None:
parts.append(str(payload["source-domain"]))
parts.append(str(payload["fidelity-type"]))
parts.append("true" if payload["did-win"] is True else "false")
parts.append(str(payload["postback-sequence-index"]))
# Join with U+2063 separator and encode to UTF-8
message_string = SEPARATOR.join(parts)
return message_string.encode('utf-8')
def verify_and_ingest_skan4_postback(postback_json_str: str) -> dict:
"""
Validates payload schema, verifies the ECDSA P-256 signature against Apple's public key,
and performs atomic transaction-id deduplication.
"""
try:
payload = json.loads(postback_json_str)
except Exception:
return {"status": "REJECTED", "reason": "INVALID_JSON_FORMAT"}
# Version Gate: Enforce SKAN 4.0 payload handling
if payload.get("version") != "4.0":
return {"status": "REJECTED", "reason": "UNSUPPORTED_SKAN_VERSION"}
# Schema Validation: Required fields for SKAN 4.0
required_fields = [
"version", "ad-network-id", "source-identifier", "app-id",
"transaction-id", "redownload", "fidelity-type", "did-win",
"postback-sequence-index", "attribution-signature"
]
for field in required_fields:
if field not in payload:
return {"status": "REJECTED", "reason": f"MISSING_REQUIRED_FIELD_{field.upper()}"}
# Strict Type Validation
if not isinstance(payload["redownload"], bool):
return {"status": "REJECTED", "reason": "INVALID_TYPE_REDOWNLOAD"}
if not isinstance(payload["did-win"], bool):
return {"status": "REJECTED", "reason": "INVALID_TYPE_DID_WIN"}
if payload["postback-sequence-index"] not in (0, 1, 2):
return {"status": "REJECTED", "reason": "INVALID_SEQUENCE_INDEX"}
if payload["fidelity-type"] not in (0, 1):
return {"status": "REJECTED", "reason": "INVALID_FIDELITY_TYPE"}
# Enforce mutual exclusivity between source-app-id and source-domain
has_source_app = payload.get("source-app-id") is not None
has_source_domain = payload.get("source-domain") is not None
if has_source_app and has_source_domain:
return {"status": "REJECTED", "reason": "CONFLICTING_SOURCE_FIELDS"}
signature_b64 = payload["attribution-signature"]
transaction_id = payload["transaction-id"]
try:
# Step 1: Reconstruct the exact UTF-8 serialized message
message_bytes = construct_skan4_message_bytes(payload)
signature_der = base64.b64decode(signature_b64, validate=True)
# Step 2: Verify ECDSA P-256 / SHA-256 signature using Apple's published public key
apple_public_key = load_der_public_key(base64.b64decode(APPLE_SKAN_PUBLIC_KEY_B64))
apple_public_key.verify(
signature_der,
message_bytes,
ec.ECDSA(hashes.SHA256())
)
except InvalidSignature:
return {"status": "REJECTED", "reason": "INVALID_CRYPTOGRAPHIC_SIGNATURE"}
except Exception as e:
return {"status": "ERROR", "reason": f"VERIFICATION_FAILED: {str(e)}"}
# Step 3: Atomic Deduplication via Redis (Hot cache layer)
# Note: In production, pair this hot cache with a persistent unique database constraint.
# 14-day TTL (1,209,600 seconds) serves as an illustrative receiver cache policy covering retries.
is_new = redis_client.set(f"skan_tx:{transaction_id}", "1", nx=True, ex=1209600)
if not is_new:
return {"status": "DUPLICATE", "reason": "TRANSACTION_ALREADY_PROCESSED"}
return {
"status": "VERIFIED",
"transaction_id": transaction_id,
"sequence_index": payload["postback-sequence-index"],
"did_win": payload["did-win"]
}
การนำโพสต์แบ็กเข้าสู่โมเดลการประมูลแบบเรียลไทม์และตัวเพิ่มประสิทธิภาพ CPA
การแยกส่วนการรับข้อมูลที่ขอบเครือข่าย (Edge Ingestion) ออกจากการประมวลผลแบบอะซิงโครนัส
DSP ที่มีปริมาณงานสูงจะประมวลผลโพสต์แบ็กจำนวนมากในช่วงที่มีแคมเปญหนาแน่น การประมวลผลแบบซิงโครนัสด้านปลายทางอาจทำให้เกิดปัญหาคอข่วนด้านความหน่วงเวลา
สถาปัตยกรรมระดับองค์กรจึงใช้ไปป์ไลน์แบบอะซิงโครนัส:
- ตัวรับที่ขอบเครือข่าย (Edge Receiver): ยอมรับคำขอ HTTP POST ที่เข้ามา ตรวจสอบความแท้จริงของลายเซ็น ดำเนินการขจัดข้อมูลซ้ำแบบอะตอมิกบน
transaction-idและส่งคืน HTTP200 OKทันที - คิวเหตุการณ์ (Event Queue): เผยแพร่เพย์โหลดที่ตรวจสอบแล้วไปยังโบรกเกอร์เหตุการณ์แบบกระจาย (เช่น Apache Kafka หรือ AWS SQS)
- เวิร์กเกอร์การประมูลและวิเคราะห์: ประมวลผลสตรีมเหตุการณ์ แมปค่าการแปลงเข้ากับตัวชี้วัดรายได้ และอัปเดตโมเดลเป้าหมาย CPA สำหรับการประมูลแบบเรียลไทม์ (RTB)
การใช้ตัวระบุแหล่งที่มาแบบลำดับชั้น (Hierarchical Source Identifier)
โพสต์แบ็กที่ชนะโพสต์แรกอาจเปิดเผยตัวเลขสอง สาม หรือสี่หลักของ source-identifier แบบลำดับชั้น ขึ้นอยู่กับระดับข้อมูลโพสต์แบ็ก ความหมายเชิงความหมายของตัวเลขเหล่านั้นถูกกำหนดโดยอนุกรมวิธาน source-identifier ของเครือข่ายโฆษณาเอง ระบบการประมูลควรแก้ไข source-identifier ที่ได้รับเทียบกับข้อมูลเมตาแคมเปญของเครือข่าย แทนที่จะสมมติว่ามีการแมปแบบสากลระหว่างความยาวของตัวเลขกับตำแหน่งเฉพาะหรือความละเอียดของชิ้นงานโฆษณา
ตารางเปรียบเทียบ: การส่งตรงจาก Apple เทียบกับการรับข้อมูลผ่าน MMP S2S
| มิติการทำงาน | การส่งตรงจาก Apple (เครือข่ายโฆษณา) | จุดสิ้นสุดของผู้พัฒนา (NSAdvertising...) |
ไปป์ไลน์การรับข้อมูล MMP S2S |
|---|---|---|---|
| ผู้รับ | เครือข่ายโฆษณาที่ลงทะเบียน | ผู้พัฒนาแอปที่ลงโฆษณา | พาร์ทเนอร์การวัดผลมือถือ (MMP) |
| ขอบเขตการระบุแหล่งที่มา | โพสต์แบ็กที่ชนะสำหรับเครือข่ายนั้นๆ | สำเนาโพสต์แบ็กที่ชนะสำหรับแอปพลิเคชัน | มุมมองรวมจากหลายเครือข่าย |
| การตรวจสอบลายเซ็น | ดำเนินการโดยแบ็กเอนด์ของเครือข่ายโฆษณา | ดำเนินการโดยแบ็กเอนด์ของผู้พัฒนา | ขึ้นอยู่กับการใช้งาน (โฟลว์ของพาร์ทเนอร์) |
| โพสต์แบ็กที่ไม่ชนะ | ได้รับหากผ่านเกณฑ์ (did-win: false) |
ไม่ส่งไปยังจุดสิ้นสุดของผู้พัฒนา | อาจมีให้ใช้งานผ่านโฟลว์ของพาร์ทเนอร์ |
| กรณีการใช้งานหลัก | การเพิ่มประสิทธิภาพการประมูลโดยตรงและเป้าหมาย CPA | การตรวจสอบและการตรวจสอบบัญชีคลังข้อมูลภายใน | แดชบอร์ดประสิทธิภาพข้ามช่องทาง |
คำถามที่พบบ่อย (FAQ)
กุญแจสาธารณะใดที่ใช้ในการตรวจสอบลายเซ็นโพสต์แบ็กของ Apple?
เหตุใดโพสต์แบ็ก SKAdNetwork ที่ถูกต้องจึงไม่ผ่านการตรวจสอบลายเซ็น?
จุดสิ้นสุดของผู้พัฒนาแอปที่ลงโฆษณาสามารถรับโพสต์แบ็ก SKAdNetwork ที่ไม่ชนะได้หรือไม่?
บทสรุปและกรอบการตัดสินใจ
การจัดการโพสต์แบ็ก SKAdNetwork ในสเกลขนาดใหญ่จำเป็นต้องมีการผสมผสานการรับข้อมูลที่ขอบเครือข่ายแบบหน่วงเวลาต่ำ เข้ากับการตรวจสอบความถูกต้องด้วยการเข้ารหัสอย่างเข้มงวดและการขจัดข้อมูลซ้ำในระดับธุรกรรม เนื่องจากโพสต์แบ็กของ Apple มีอิทธิพลโดยตรงต่อการจัดสรรงบประมาณและอัลกอริทึมการประมูล การตรวจสอบลายเซ็น ECDSA และการบังคับใช้ความสมมูลของ transaction-id จึงช่วยปกป้องไปป์ไลน์การรับข้อมูลจากโพสต์แบ็กที่ถูกปลอมแปลงหรือถูกดัดแปลง รวมถึงการประมวลผลการเล่นซ้ำที่ซ้ำซ้อน
เพื่อเสริมการรายงาน SKAdNetwork ที่สื่อกลางโดยแพลตฟอร์ม ด้วยกระบวนการเริ่มต้นใช้งานผู้ใช้ระดับไมโครและการกำหนดเส้นทางลิงก์เชิงลึกทันที ทีมวิศวกรรมจึงปรับใช้สถาปัตยกรรมการกำหนดเส้นทางแบบเฟิร์สพาร์ที้ควบคู่ไปกับ API ของแพลตฟอร์ม
หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับการกำหนดค่าโพสต์แบ็กการระบุแหล่งที่มาฝั่งเซิร์ฟเวอร์และไปป์ไลน์ลิงก์เชิงลึก โปรดตรวจสอบ เอกสารประกอบของ OpoInstall
วัสดุที่เกี่ยวข้อง
-
แนวคิด: โพสต์แบ็ก S2S, การตรวจสอบด้วยการเข้ารหัส, ECDSA P-256, การป้องกันการโจมตีแบบ Replay Attack, การขจัดข้อมูลธุรกรรมซ้ำ
-
เทคโนโลยี: Apple SKAdNetwork, Apple AdAttributionKit, Redis In-Memory Cache, OpoInstall Mobile SDK
-
มาตรฐาน: IETF RFC 8259 (การแลกเปลี่ยนข้อมูล JSON), RFC 5480 (การเข้ารหัสลับเส้นโค้งวงรี)
-
API: StoreKit SKAdNetwork API, ข้อมูลจำเพาะการส่งโพสต์แบ็ก Apple S2S, OpoInstall S2S API
เอกสารประกอบอย่างเป็นทางการ
-
เอกสารประกอบสำหรับนักพัฒนาของ Apple เกี่ยวกับการตรวจสอบโพสต์แบ็กยืนยันการติดตั้ง
-
เอกสารประกอบสำหรับนักพัฒนาของ Apple เกี่ยวกับการระบุพารามิเตอร์ในโพสต์แบ็กยืนยันการติดตั้ง
-
เอกสารประกอบสำหรับนักพัฒนาของ Apple เกี่ยวกับการกำหนดค่าแอปพลิเคชันที่ลงโฆษณา
-
เอกสารประกอบสำหรับนักพัฒนาของ Apple เกี่ยวกับ AdAttributionKit
Share this article



