היסודות של API לצבירה פרטית

מושגי מפתח של Private Aggregation API

למי מיועד המסמך הזה?

Private Aggregation API מאפשר איסוף נתונים מצטברים מ-worklets עם גישה לנתונים באתרים שונים. המושגים שמתוארים כאן חשובים למפתחים שיוצרים דוחות ב-Shared Storage וב-Protected Audience API.

  • אם אתם מפתחים שיוצרים מערכת דיווח לאתרים שונים מדידה.
  • אם אתם משווקים, מדעני נתונים או צרכנים אחרים של דוחות סיכום, הבנת המנגנונים האלה תעזור לכם לקבל החלטות לגבי העיצוב כדי לאחזר דוח סיכום מותאם.

מונחי מפתח

לפני שתקרא את המסמך הזה, כדאי להכיר: מונחי מפתח ומושגים מרכזיים. כל אחד מהמונחים האלה יתאר כאן בפירוט.

  • מפתח צבירה (שנקרא גם קטגוריה) הוא מוגדר מראש של נקודות נתונים. לדוגמה, יכול להיות שתרצו לאסוף קטגוריה של נתוני מיקום שבה הדפדפן מדווח על שם המדינה. מפתח צבירה עשוי להכיל יותר ממאפיין אחד (לדוגמה, המדינה והמזהה של ווידג'ט התוכן).
  • ערך מצטבר הוא נקודה על הגרף. שנאספים למפתח צבירה. אם רוצים למדוד כמה משתמשים מצרפת צפו בתוכן, הערך France הוא מאפיין במפתח הצבירה, והערך viewCount של 1 הוא הערך שאפשר לצבור.
  • דוחות נצברים נוצרים ומוצפנים בתוך דפדפן. ב-Private Aggregation API, הנתונים האלה מכילים נתונים על אירוע יחיד.
  • שירות הצבירה מעבד נתונים מדוחות שאפשר לצבור כדי ליצור דוח סיכום.
  • דוח סיכום הוא הפלט הסופי של שירות האגרגציה, והוא מכיל נתוני משתמשים נצברים עם רעש ונתוני המרות מפורטים.
  • worklet הוא קטע של תשתית שמאפשרת להריץ פונקציות JavaScript ספציפיות להחזיר מידע אל המבקש. בתוך רכיב worklet אפשר להריץ JavaScript, אבל אי אפשר לבצע אינטראקציה או לתקשר עם הדף החיצוני.

תהליך העבודה של Private Aggregation

כשקוראים ל-Private Aggregation API עם מפתח צבירה וערך שניתן לצבור, הדפדפן יוצר דוח שניתן לצבור. הדוחות נשלחים לשרת שלכם, שמקבץ אותם. המערכת מעבדת את הדוחות בקבוצות מאוחר יותר באמצעות שירות הצבירה, ויוצרת דוח סיכום.

הנתונים עוברים מהלקוח לאוסף, ולאחר מכן לשירות הצבירה כדי ליצור דוח סיכום.
  1. כשאתם קוראים ל-Private Aggregation API, הלקוח (הדפדפן) יוצר את הדוח שאפשר לצבור ומעביר אותו לשרת שלכם כדי שייאסף.
  2. השרת אוסף את הדוחות מהלקוחות ומקבץ אותם לקבוצות כדי לשלוח אותן לשירות הצבירה.
  3. אחרי שתאספו מספיק דוחות, תחלקו אותם ותשלחו אותם אל שירות צבירה, שפועל בסביבת הפעלה מהימנה, כדי ליצור דוח סיכום.

תהליך העבודה שמתואר בקטע הזה דומה ל-Attribution Reporting API. עם זאת, דיווח על שיוך (Attribution) משייך נתונים שנאספו מאירוע חשיפה ומאירוע המרה, שמתרחשים בזמנים שונים. באמצעות צבירת נתונים פרטית אפשר למדוד אירוע יחיד באתרים שונים.

מפתח צבירה

מפתח צבירת נתונים (או 'מפתח' בקיצור) מייצג את הקטגוריה שבה יתצברו הערכים שאפשר לצבור. אפשר לקודד מאפיינים אחד או יותר במפתח. מאפיין מייצג היבט מסוים שברצונך לקבל תובנות בנושא, כמו קבוצת הגיל של המשתמשים או מספר החשיפות של מודעה .

לדוגמה, נניח שיש לכם ווידג'ט שמוטמע בכמה אתרים אם אתם רוצים לנתח את המדינה של המשתמשים שראו את הווידג'ט שלכם. אתם רוצים לקבל תשובות לשאלות כמו "כמה מהמשתמשים שראו את הווידג'ט שלי הם ממדינה X?" כדי לדווח על השאלה הזו, אפשר להגדיר מפתח צבירת נתונים שמקודד שני מאפיינים: מזהה הווידג'ט ומזהה המדינה.

המפתח שסופק ל-Private Aggregation API הוא BigInt, שמורכב מכמה מאפיינים. בדוגמה הזו, המאפיינים הם מזהה הווידג'ט ומזהה המדינה. נניח שמזהה הווידג'ט יכול להכיל עד 4 ספרות ארוך כמו 1234, וכל מדינה ממופה למספר מסוים בסדר אלפביתי הזמנה כמו אפגניסטן היא 1, צרפת היא 61 וזימבבואה הוא '195'. לכן, המפתח המצטבר יהיה באורך של 7 ספרות, כאשר 4 התווים שמורים לWidgetID ו-3 התווים האחרונים הם שמורים ל-CountryID.

נניח שהמפתח מייצג את מספר המשתמשים מצרפת (מזהה המדינה 061) שראו את מזהה הווידג'ט 3276. מפתח הצבירה הוא 3276061.

מפתח צבירת נתונים
מזהה ווידג'ט מזהה מדינה
3276 061

ניתן ליצור את מפתח הצבירה גם באמצעות מנגנון גיבוב, כמו SHA-256. לדוגמה, אפשר לבצע גיבוב של המחרוזת {"WidgetId":3276,"CountryID":67} ואז להמיר אותה לערך BigInt של 42943797454801331377966796057547478208888578253058197330928948081739249096287n. אם ערך הגיבוב כולל יותר מ-128 ביטים, אפשר לחתוך אותו כדי להבטיח שהוא לא יפעל חריגה מהערך המקסימלי המותר של 2^128−1 בקטגוריה.

בתוך worklet של Shared Storage, אפשר לגשת crypto ו- TextEncoder מודולים שיכול לעזור לכם ליצור גיבוב. לקבלת מידע נוסף על יצירת גיבוב (hash), אפשר לעבור אל SubtleCrypto.digest() במצב פעיל MDN

הדוגמה הבאה מתארת איך אפשר ליצור מפתח קטגוריה ממפתח מגובב (hashed) ערך:

async function convertToBucket(data) {
  // Encode as UTF-8 Uint8Array
  const encodedData = new TextEncoder().encode(data);

  // Generate SHA-256 hash
  const hashBuffer = await crypto.subtle.digest('SHA-256', encodedData);

  // Truncate the hash
  const truncatedHash = Array.from(new Uint8Array(hashBuffer, 0, 16));

  // Convert the byte sequence to a decimal
  return truncatedHash.reduce((acc, curr) => acc * 256n + BigInt(curr), 0n);
}

const data = {
  WidgetId: 3276,
  CountryID: 67
};

const dataString = JSON.stringify(data);
const bucket = await convertToBucket(dataString);

console.log(bucket); // 126200478277438733997751102134640640264n

ערך צבירת נתונים

ערכים שאפשר לצבור מתווספים לפי מפתח בקרב משתמשים רבים כדי ליצור תובנות מצטברות בצורת ערכים של סיכומים בדוחות סיכום.

עכשיו נחזור לשאלה לדוגמה שהוצגה למעלה: "כמה משתמשים מי ראו את הווידג'ט שלי הם מצרפת?" התשובה לשאלה הזו תיראה משהו כמו "בערך 4881 משתמשים שראו את מזהה הווידג'ט 3276 שלי הם from France." הערך aggregatable הוא 1 לכל משתמש, והערך '4881 משתמשים' הוא הערך המצטבר שהוא הסכום של כל הערכים aggregatable באותו מפתח צבירת נתונים.

מפתח צבירת נתונים ערך שניתן לצבור
מזהה ווידג'ט מזהה מדינה מספר צפיות
3276 061 1

לצורך הדוגמה הזו, אנחנו מעלים את הערך ב-1 לכל משתמש שרואה את הווידג'ט. בפועל, אפשר לשנות את הערך שאפשר לצבור כדי לשפר את יחס האות לרעש.

תקציב התרומות

כל קריאה ל-Private Aggregation API נקראת תרומה. כדי להגן על פרטיות המשתמשים, מספר התרומות שאפשר לקבל מאדם מסוים מוגבל.

כאשר מחברים את כל הערכים המצטברים בכל מפתחות הצבירה, הסכום חייב יהיו נמוכות מהתקציב לתרומה. התקציב הוא בהיקף לפי עבודה origin, ליום, ו- בנפרד ל-Protected Audience API ול-worklets של Shared Storage. גלגול חלון של כ-24 השעות האחרונות משמש עבור היום. אם תג חדש דוח המצטבר יגרום לחריגה מהתקציב, נוצר.

תקציב התרומה מיוצג על ידי הפרמטר L1, מוגדר ל-216 (65,536) לעשר דקות ביום עם עצירת ביניים של 220

(1,048,576). למידע נוסף על הפרמטרים האלה, קראו את הסבר.

הערך של תקציב התרומה הוא שרירותי, אבל רמת הרעש מותאמת אליו. אפשר להשתמש בתקציב הזה כדי למקסם את יחס האות לרעש בערכים הסיכומיים (מידע נוסף זמין בקטע רעש ושינוי קנה מידה).

מידע נוסף על תקציבים לתרומות זמין במאמר הזה. כמו כן, אפשר לעיין בקטע תרומה Budget (תקציב) לקבלת הנחיות נוספות.

מגבלת התרומות לכל דוח

מגבלת התרומה עשויה להשתנות בהתאם למתקשר. בשלב זה, הדוחות שנוצרים למפעילי Shared Storage API מוגבלים ל-20 תרומות לכל דוח. לעומת זאת, למבצעים של קריאות ל-Protected Audience API מוקצית מכסה של 100 תרומות לכל דוח. המגבלות האלה נבחרו כדי לאזן בין מספר התכנים שאפשר להטמיע לבין גודל המטען הייעודי.

באחסון משותף, תרומות שבוצעו בפעולה אחת של run() או selectURL() מקובצות בדוח אחד. כשמשתמשים ב-Protected Audience, תרומות שמקורות שונים תורמים במכרז מסוים מקובצות יחד.

תכנים שנוספו עם מרווח פנימי

בנוסף, הוספת תוכן מתבצעת באמצעות תכונת מרווח פנימי. הוספת נתונים לתוכן המועמס (padding) מגינה על המידע לגבי המספר האמיתי של התרומות שמוטמעות בדוח שאפשר לצבור. כדי להגיע לאורך קבוע, המרווח מוסיף לעומס התועלת null ערכים (כלומר ערך של 0).

דוחות שאפשר לצבור

אחרי שהמשתמש מפעיל את Private Aggregation API, הדפדפן יוצר דוחות שניתן לצבור, ששירות הצבירה יעבד בשלב מאוחר יותר כדי ליצור דוחות סיכום. דוח שניתן לצבור הוא בפורמט JSON ומכיל רשימה מוצפנת של תרומות, שכל אחת מהן היא זוג {aggregation key, aggregatable value}. דוחות שאפשר לצבור נשלחים עם עיכוב אקראי של עד שעה.

התכנים שנוספו מוצפנים ואי אפשר לקרוא אותם מחוץ ל-Aggregation Service. שירות הצבירה מפענח את הדוחות ויוצר דוח סיכום. למפתח ההצפנה של הדפדפן והמפתח לפענוח של נתוני הצבירה השירות מונפקת על ידי המתאם, שמשמש כשירות ניהול מפתחות. המתאם שומר רשימה של גיבובים בינאריים של תמונת השירות כדי לאמת שהמתקשר רשאי לקבל את מפתח הפענוח.

דוגמה לדוח שניתן לצבור כשמצב ניפוי הבאגים מופעל:

  "aggregation_service_payloads": [
    {
      "debug_cleartext_payload": "omRkYXRhgaJldmFsdWVEAAAAgGZidWNrZXRQAAAAAAAAAAAAAAAAAAAE0mlvcGVyYXRpb25paGlzdG9ncmFt",
      "key_id": "2cc72b6a-b92f-4b78-b929-e3048294f4d6",
      "payload": "a9Mk3XxvnfX70FsKrzcLNZPy+00kWYnoXF23ZpNXPz/Htv1KCzl/exzplqVlM/wvXdKUXCCtiGrDEL7BQ6MCbQp1NxbWzdXfdsZHGkZaLS2eF+vXw2UmLFH+BUg/zYMu13CxHtlNSFcZQQTwnCHb"
    }
  ],
  "debug_key": "777",
  "shared_info": "{\"api\":\"shared-storage\",\"debug_mode\":\"enabled\",\"report_id\":\"5bc74ea5-7656-43da-9d76-5ea3ebb5fca5\",\"reporting_origin\":\"https://localhost:4437\",\"scheduled_report_time\":\"1664907229\",\"version\":\"0.1\"}"

ניתן לבחון את הדוחות המצטברים דף chrome://private-aggregation-internals:

צילום מסך של הדף 'הרכיבים הפנימיים של Private Aggregation API'

למטרות בדיקה, העמודה "שליחת דוחות נבחרים" יכול לשמש לשליחת הלחצן לדווח לשרת באופן מיידי.

איסוף דוחות שניתן לצבור אותם בקבוצה

הדפדפן שולח את הדוחות המצטברים למקור של ה-worklet שמכיל את הקריאה ל-Private Aggregation API, באמצעות path:

  • לנפח אחסון משותף: /.well-known/private-aggregation/report-shared-storage
  • לקהל מוגן: /.well-known/private-aggregation/report-protected-audience

בנקודות הקצה האלה תצטרכו להפעיל שרת – שמשמש כקולקטור – שמקבל את הדוחות שאפשר לצבור שנשלחים מהלקוחות.

לאחר מכן השרת צריך לקבץ דוחות ולשלוח את קיבוץ הנתונים לצבירה שירות. יצירת קבוצות קבצים על סמך המידע שזמין בקובץ ללא הצפנה המטען הייעודי (payload) של הדוח המצטבר, כמו השדה shared_info. מומלץ שהקבוצות יכילו 100 דוחות או יותר.

אפשר להחליט אם לקבץ את התוצאות על בסיס יומי או שבועי. זוהי שיטה גמישה, ואפשר לשנות את שיטת הקיבוץ לאירועים ספציפיים שבהם צפוי נפח גדול יותר – לדוגמה, ימים בשנה שבהם צפויים יותר חשיפות. הקבוצות צריכות לכלול דוחות מאותה גרסת API, מקור הדיווח, לתזמן את מועד הדיווח.

Aggregation Service

השירות פועל בסביבת TEE, מפענח את הדוחות המצטברים ומוסיף
רעש כדי ליצור את דוח הסיכום הסופי.

שירות האגרגציה מקבל מהאוסף דוחות מוצפנים שניתן לאסוף אותם ויוצר דוחות סיכום.

כדי לפענח את המטען הייעודי (payload) של הדוח, שירות הצבירה מאחזר מפתח פענוח מהמתאם. השירות פועל בסביבת הפעלה מהימנה (TEE), שמספק רמת ודאות לתקינות הנתונים, לסודיות הנתונים ותקינות הקוד. אתם הבעלים של השירות ומפעילים אותו, אבל לא תהיה לכם גישה לנתונים שעוברים עיבוד ב-TEE.

דוחות סיכום

דוחות סיכום מאפשרות לראות את הנתונים שאספתם עם הרעש שנוסף. אפשר לבקש דוחות סיכום עבור קבוצה נתונה של מפתחות.

דוח סיכום מכיל קבוצה של צמדי מפתח/ערך בסגנון מילון JSON. כל אחד צמד מכיל:

  • bucket: מפתח הצבירה כמחרוזת של מספר בינארי. אם מפתח הצבירה שבו נעשה שימוש הוא '123', הקטגוריה תהיה '1111011'.
  • value: הערך הסיכום של יעד מדידה נתון, שמסוכם מ: כל הדוחות המצטברים הזמינים שכוללים רעש שנוסף.

לדוגמה:

[
  {"bucket":` `"111001001",` `"value":` `"2558500"},
  {"bucket":` `"111101001",` `"value":` `"3256211"},
  {"bucket":` `"111101001",` `"value":` `"6536542"},
]

רעש ושינוי גודל

כדי לשמור על פרטיות המשתמשים, שירות הצבירה מוסיף רעש פעם אחת ערך סיכום בכל פעם שנשלחת בקשה לדוח סיכום. ערכי הרעש נשלפים באופן אקראי מהתפלגות הסתברות של Laplace. בזמן ביצוע אין שליטה ישירה על אופן הוספת הרעש, של רעשי רקע בנתוני המדידה שלו.

התפלגות הרעשים זהה, ללא קשר לסכום של כל ערכים. לכן, ככל שהערכים המצטברים גבוהים יותר, כך ההשפעה של הרעש תהיה נמוכה יותר. שיש סבירות גבוהה ביותר.

לדוגמה, נניח שבהתפלגות הרעש יש סטיית תקן של 100. וממורכז ב-0. אם הערך שנאסף בדוח המצטבר (או 'ערך מצטבר') הוא רק 200, אז סטיית התקן של הרעש תהיה 50% מהערך המצטבר. אבל אם הערך המצטבר הוא 20,000, אז סטיית התקן של הרעש תהיה רק 0.5% מהערך המצטבר. לכן, לערך המצטבר של 20,000 תהיה יחס אות/רעש גבוה בהרבה.

לכן, הכפלת הערך שאפשר לצבור בגורם שינוי יכולה לעזור לצמצם את הרעש. גורם קנה המידה מייצג את המידה שבה ברצונך להתאים את הגודל כערך מצטבר.

הרעש הוא קבוע, ללא קשר לערך המצטבר.

הגדלת הערכים על ידי בחירה בגורם גדול יותר לקביעת קנה מידה מפחיתה את הרעש היחסי. עם זאת, הפעולה הזו גם גורמת לסך כל התכנים שנוספו בכל הקטגוריות כדי להגיע מהר יותר למגבלת התקציב לתרומות. העלאת הערכים כלפי מטה ב- בחירת גורם הגדלה קטן יותר באופן קבוע מגבירה את הרעש היחסי, אבל מפחיתה את הסיכון של הגעה למגבלת התקציב.

משנים את הערך שאפשר לצבור בהתאם לתקציב התרומה.

כדי לחשב גורם מתאים להגדלה, צריך לחלק את תקציב התרומה ב- הסכום המקסימלי של הערכים המצטברים בכל המפתחות.

למידע על תקציב התרומות תיעוד למידע נוסף.

מעורבות ושיתוף משוב

אנחנו עדיין בוחנים את Private Aggregation API ועשויים לשנות אותו בעתיד. אם תנסו את ה-API הזה ותהיה לכם משוב, נשמח לשמוע אותו.