אם בעלי אתרים מעבירים ל-Authorized Buyers נתוני מיקום לנייד שהם ספציפיים יותר ממיקוד, הקונים המורשים ישלחו גידור גיאוגרפי של קונים בשדה מוצפן חדש: BidRequest.encrypted_hyperlocal_set
.
ציר הזמן
- משתמש מתקין אפליקציה לנייד שנתמכת על ידי מודעות, ומביע הסכמה לאפליקציה בגישה למיקום המכשיר ושיתוף שלו עם צדדים שלישיים. האפליקציה הזו גם משולבת ב-Google Ads SDK ושולחת את מיקום המכשיר אל Google.
- השרתים של Google מייצרים אות טירגוט מקומי ספציפי במיוחד שמייצג את גדר הגבול הגיאוגרפי סביב מיקום המכשיר, למשל כדי להגן על פרטיות המשתמש.
- שרתי Google מסדרים ולהצפין את אות הטירגוט ההיפר-מקומי באמצעות מפתח האבטחה הספציפי לכל קונה. לידיעתך, מגיש הצעת המחיר מסתמך על אותו מפתח כדי לפענח את המאקרו WINNING_PRICE.
- מגיש הצעת המחיר מפענח ומבטלים סידור מחדש של אות הטירגוט ההיפר-מקומי למאגר פרוטוקול. לאחר מכן מגיש הצעת המחיר יכול לנתח את האות ולבחור הצעת מחיר בהתאם.
יחסי תלות
צריכה להיות לכם ספריית הצפנה שתומכת ב-HMAC של SHA-1, כמו Openssl.
הגדרה
אות טירגוט ספציפי למיקום מוגדר בפרוטוקול הזה:
// A hyperlocal targeting location when available. // message Hyperlocal { // A location on the Earth's surface. // message Point { optional float latitude = 1; optional float longitude = 2; } // The mobile device can be at any point inside the geofence polygon defined // by a list of corners. Currently, the polygon is always a parallelogram // with 4 corners. repeated Point corners = 1; } message HyperlocalSet { // This field currently contains at most one hyperlocal polygon. repeated Hyperlocal hyperlocal = 1; // The approximate geometric center of the geofence area. It is calculated // exclusively based on the geometric shape of the geofence area and in no // way indicates the mobile device's actual location within the geofence // area. If multiple hyperlocal polygons are specified above then // center_point is the geometric center of all hyperlocal polygons. optional Hyperlocal.Point center_point = 2; } // Hyperlocal targeting signal when available, encrypted as described at // https://developers.google.com/authorized-buyers/rtb/response-guide/decrypt-hyperlocal optional bytes encrypted_hyperlocal_set = 40;
כל אות של טירגוט מקומי- רכבי נמצא בפוליגון אחד או יותר ובנקודה מרכזית אחת. עבור כל פוליגון, אות הטירגוט ההיפר-מקומי מכיל:
- קו הרוחב וקו האורך של כל פינה במצולע ברצף,
עוברים כשדה חוזר
corners
. - המרכז הגיאומטרי המשוער של אזור הגבול הווירטואלי, שעבר בשדה האופציונלי
center_point
.
המבנה של אות מיקוד
אות הטירגוט הנפרד המקומי המוצפן שנמצא ב-BidRequest.encrypted_hyperlocal_set
מכיל 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
, ה-20 בייט התואמים של ciphertext
נוצר כך:
<byte_array <xor> HMAC(encryption_key, initialization_vector || counter_bytes)>
כאשר ||
הוא שרשור.
הגדרות
משתנה | פרטים |
---|---|
initialization_vector |
16 בייטים – ייחודיים לחשיפה. |
encryption_key |
32 בייטים – שסופקו בהגדרת החשבון. |
integrity_key |
32 בייטים – שסופקו בהגדרת החשבון. |
byte_array |
אובייקט HyperlocalSet סידורי, בקטעים של 20 בייט. |
counter_bytes |
ערך בייטים שמראה את המספר הסידורי של הקטע, כמפורט למטה. |
final_message |
מערך בייטים שנשלח באמצעות השדה BidRequest.encrypted_hyperlocal_set . |
מפעילים | פרטים |
---|---|
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 | בייט אחד. הערך גדל בין 0 ל-255 ברציפות. |
257 ... 512 | שני בייטים. הערך של הבייט הראשון הוא 0, הערך של הבייט השני גדל מ-0 ל-255 ברציפות. |
513 ... 768 | שלושה בייטים. הערך של שני הבייטים הראשונים הוא 0, הערך של הבייט האחרון גדל מ-0 ל-255 ברציפות. |
אנחנו לא צופים שהאורך של BidRequest.encrypted_hyperlocal_set
יעלה על קילובייט אחד, גם אם
אנחנו לוקחים בחשבון צמיחה נוספת. עם זאת, counter_bytes
יכול להיות באורך הנדרש כדי לתמוך באות טירגוט היפר-מקומי של אורך שרירותי.
סכמת הצפנה
סכמת ההצפנה לאות טירגוט מקומי מקומי מבוססת על אותה סכימה המשמשת לאישור מחירים.
סנכרון סידורי: האות ההיפר-מקומי של הטירגוט, שהוא מופע של האובייקט HyperlocalSet כפי שהוגדר בפרוטו, עובר עיבוד ראשון דרך
SerializeAsString()
למערך בייט.הצפנה: לאחר מכן, מערך הבייטים מוצפן באמצעות סכימת הצפנה מותאמת אישית שנועדה לצמצם את תקורת הגודל תוך הקפדה על אבטחה הולמת. בסכמת ההצפנה נעשה שימוש באלגוריתם HMAC חשוב כדי ליצור לוח סודי המבוסס על
initialization_vector
, שהוא ייחודי לאירוע החשיפה.
פסאודו-הצפנה של הצפנה
byte_array = SerializeAsString(HyperlocalSet 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)
שכפול פענוח
(initialization_vector, ciphertext, integrity_signature) = final_message // split up according to length rules pad = hmac(encryption_key, initialization_vector || counter_bytes) // for each 20-byte section of ciphertext byte_array = ciphertext <xor> pad // for each 20-byte section of ciphertext 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'); } } }
דוגמה לאות ומפתחות היפר-מקומיים
כדי לבדוק ולאמת את הקוד:
- ממירים מחרוזת שמכילה 308 תווים הקסדצימליים למערך של 154 בייטים. לדוגמה, בהתאם למחרוזת הבאה:
E2014EA201246E6F6E636520736F7572636501414243C0ADF6B9B6AC17DA218FB50331EDB376701309CAAA01246E6F6E636520736F7572636501414243C09ED4ECF2DB7143A9341FDEFD125D96844E25C3C202466E6F6E636520736F7572636502414243517C16BAFADCFAB841DE3A8C617B2F20A1FB7F9EA3A3600256D68151C093C793B0116DB3D0B8BE9709304134EC9235A026844F276797
ממירה אותו למערך בנפח 154 בייט באופן הבא:const char serialized_result[154] = { 0xE2, 0x01, 0x4E, ... };
- יש לקרוא לשיטה
BidRequest.ParsePartialFromString()
כדי להסיר את מערך ה-154 בייט למאגר פרוטוקולBidRequest
.BidRequest bid_req; bid_req.ParsePartialFromString(serialzed_result);
- מוודאים שיש ב-
BidRequest
רק שלושה שדות:encrypted_hyperlocal_set
בוצעה הצהרה בהודעהBidReqeust
.encrypted_advertising_id
בוצעה הצהרה בהודעהBidReqeust.Mobile
.encrypted_hashed_idfa
בוצעה הצהרה בהודעהBidReqeust.Mobile
.
למשל:
encrypted_hyperlocal_set:( { 100, 100 }, { 200, -300 }, { -400, 500 }, { -600, -700 },) encrypted_advertising_id: { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11 } encrypted_hashed_idfa : { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0xF1 }
- משתמשים בשדות
encryption_key
ו-integrity_key
הבאים כדי לפענח את 3 השדות ולאמת שהם מפענחים אותם נכון.encryption_key = {0x02, 0xEE, 0xa8, 0x3c, 0x6c, 0x12, 0x11, 0xe1, 0x0b, 0x9f, 0x88, 0x96, 0x6c, 0xee, 0xc3, 0x49, 0x08, 0xeb, 0x94, 0x6f, 0x7e, 0xd6, 0xe4, 0x41, 0xaf, 0x42, 0xb3, 0xc0, 0xf3, 0x21, 0x81, 0x40}; integrity_key = {0xbf, 0xFF, 0xec, 0x55, 0xc3, 0x01, 0x30, 0xc1, 0xd8, 0xcd, 0x18, 0x62, 0xed, 0x2a, 0x4c, 0xd2, 0xc7, 0x6a, 0xc3, 0x3b, 0xc0, 0xc4, 0xce, 0x8a, 0x3d, 0x3b, 0xbd, 0x3a, 0xd5, 0x68, 0x77, 0x92};
זיהוי של מתקפות תגובה לא עדכניות
כדי לזהות מתקפות של תגובות מיושןות, אנחנו ממליצים לסנן תגובות עם חותמת זמן שונה באופן משמעותי מתקופת המערכת, אחרי להביא בחשבון הבדלים בין אזורי זמן. השרתים שלנו מוגדרים לזמן PST/PDT.
לפרטים על הטמעה, ניתן לעיין במאמר 'זיהוי תקיפות של תגובות מיושן' במאמר פענוח של אישור מחירים.
ספריית Java
במקום להטמיע את האלגוריתמים של הקריפטו לצורך קידוד ופענוח של אותות הטירגוט המקומי, אפשר להשתמש ב- DoubleClickCrypto.Java. למידע נוסף, ראו קריפטוגרפיה.