רשתות מודעות שמשתמשות ב-
תגי JavaScript למילוי מודעות דרך Authorized Buyers עומדים בדרישות
לקבל מזהי מפרסמים גם במכשירי Android וגם במכשירי iOS.
המידע נשלח באמצעות %%EXTRA_TAG_DATA%%
או
מאקרו %%ADVERTISING_IDENTIFIER%%
בתג JavaScript מנוהל
על ידי Authorized Buyers. החלק הבא מתמקד בחילוץ
%%EXTRA_TAG_DATA%%
אבל לראות
רימרקטינג עם IDFA או מזהה פרסום לפרטים נוספים
במאגר הנתונים הזמני של Proto המוצפן %%ADVERTISING_IDENTIFIER%%
MobileAdvertisingId
שאפשר לפענח אותו באופן מקביל.
ציר הזמן
- רשת המודעות מעדכנת את תגי ה-JavaScript באפליקציות שלה
דרך ממשק המשתמש של Authorized Buyers,
מוסיפים את המאקרו
%%EXTRA_TAG_DATA%%
כמו שמוסבר בהמשך. - בזמן הצגת המודעות, האפליקציה מבקשת להציג מודעה מ-Authorized Buyers דרך Google Mobile Ads SDK, או העברה מאובטחת של מזהה המפרסם.
- האפליקציה מקבלת בחזרה את תג ה-JavaScript, עם הערך
%%EXTRA_TAG_DATA%%
מלא את המאקרו במאגר הנתונים הזמני של פרוטוקול רשת המודעות המוצפן, שמכיל את המזהה הזה. - האפליקציה מפעילה את התג הזה ומבצעת קריאה לרשת המודעות של המודעה.
- כדי להשתמש במידע הזה (לייצר הכנסות) ממנו, רשת המודעות צריכה לעבד
מאגר הנתונים הזמני של הפרוטוקול:
- מפענחים את המחרוזת websafe חזרה ל-bytestring באמצעות WebSafeBase64.
- פרשו אותה באמצעות הסכמה המתוארת בהמשך.
- מבצעים פעולת deserialing של הפרוטו ומשיגים את מזהה המפרסם מה: ExtraTagData.reporting_id או ExtraTagData.hashed_idfa.
יחסי תלות
- פלטפורמת WebSafeBase64 המקודד.
- ספריית הצפנה שתומכת ב-SHA-1 HMAC, כמו Openssl.
- פרוטוקול Google באמצעות מהדר במאגרי נתונים זמניים.
פענוח המחרוזת ל-websafe
כי המידע נשלח דרך פקודת המאקרו %%EXTRA_TAG_DATA%%
צריך להישלח דרך כתובת URL, ושרתי Google מקודדים אותה באמצעות base64 בטוח לאינטרנט (RFC 3548).
לפני הניסיון לכן צריך לפענח את תווי ה-ASCII בחזרה bytestring. קוד 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); }
המבנה של bytestring מוצפן
אחרי שתפענחו את תווי ה-ASCII בחזרה ל-bytestring, תוכלו להתחיל כדי לפענח אותו. ה-bytestring המוצפן מכיל 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 |
אובייקט ExtraTagData שעבר סריאליזציה, בקטעים של 20 בייטים. |
counter_bytes |
ערך בייט שמציג את המספר הסידורי של הקטע, כפי שמפורט בהמשך. |
final_message |
מערך בייטים כולל שנשלח באמצעות המאקרו %%EXTRA_TAG_DATA%% (פחות הקידוד WebSafeBase64). |
אופרטורים | פרטים |
---|---|
hmac(key, data) |
SHA-1 HMAC, באמצעות key כדי להצפין את data . |
a || b |
המחרוזת a משורשרת למחרוזת b . |
חשבו Count_bytes
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()
למערך בייטים.Encryption: מערך הבייטים מוצפן לאחר מכן באמצעות סכימת הצפנה מותאמת אישית שנועדה למזער את תקורת הגודל, תוך הקפדה על אבטחה הולמת. סכימת ההצפנה משתמשת באלגוריתם 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>
עם מידע מוצפן (ciphertext) כדי להפוך את ההצפנה. - אימות: חתימת התקינות מעבירה 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%%
, אפשר לבצע פעולת deserialize לשטח האחסון הזמני של הפרוטוקול
ולקבל את מזהה המפרסם לטירגוט.
אם אתם לא מכירים את השימוש במאגרי נתונים זמניים בפרוטוקולים, מתחילים עם התיעוד שלנו.
הגדרה
מאגר הפרוטוקול של רשת מודעות שלנו מוגדר כך:
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; }
צריך לבצע פעולת deserialize באמצעות ParseFromString()
כמו שמתואר
מסמכי תיעוד של מאגר הנתונים הזמני של פרוטוקול C++.
לפרטים על advertising_id
Android ועל iOS
hashed_idfa
שדות, לעיון בפענוח
מזהה פרסום וטירגוט לאפליקציה לנייד
מלאי שטחי פרסום עם IDFA.
ספריית Java
במקום להטמיע את האלגוריתמים לקריפטו כדי לקודד ולפענח במזהי המפרסמים לרשתות של מודעות, אפשר להשתמש DoubleClickCrypto.java. מידע נוסף זמין במאמר הבא: קריפטוגרפיה.