Local Database

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

רשימות זמינות

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

הרשימות הבאות זמינות לשימוש בשיטות של רשימות גיבוב.

שם רשימה הטיפוס בן המנייה (enum) התואם של ThreatType בגרסה 4 תיאור
gc-32b ללא הרשימה הזו היא רשימת Global Cache. זוהי רשימה מיוחדת שמשמשת רק במצב הפעולה 'זמן אמת'.
se-4b SOCIAL_ENGINEERING הרשימה הזו מכילה איומים מסוג SOCIAL_ENGINEERING.
mw-4b MALWARE הרשימה הזו מכילה איומים מסוג תוכנה זדונית בפלטפורמות למחשב.
uws-4b UNWANTED_SOFTWARE הרשימה הזו מכילה איומים מסוג UNWANTED_SOFTWARE בפלטפורמות למחשב.
uwsa-4b UNWANTED_SOFTWARE הרשימה הזו מכילה איומים מסוג UNWANTED_SOFTWARE בפלטפורמות Android.
pha-4b POTENTIALLY_HARMFUL_APPLICATION הרשימה הזו מכילה איומים מסוג POTENTIALLY_HARMFUL_APPLICATION לפלטפורמות Android.

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

עדכוני מסדי נתונים

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

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

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

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

פענוח תוכן הרשימה

פענוח גיבובים וקידומות של גיבובים

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

נניח שצריך להעביר שלושה ביטויים של תחילית נתיב עם סיומת מארח, כלומר a.example.com/,‏ b.example.com/ ו-y.example.com/, באמצעות תחיליות גיבוב באורך 4 בייטים. נניח גם שהפרמטר של Rice, שמצוין ב-k, נבחר להיות

  1. השרת יתחיל בכך שיחשב את הגיבוב המלא של המחרוזות האלה, שהן, בהתאמה:
291bc5421f1cd54d99afcc55d166e2b9fe42447025895bf09dd41b2110a687dc  a.example.com/
1d32c5084a360e58f1b87109637a6810acad97a861a7769e8f1841410d2a960c  b.example.com/
f7a502e56e8b01c6dc242b35122683c9d25d07fb1f532d9853eb0ef3ff334f03  y.example.com/

לאחר מכן, השרת יוצר תחיליות גיבוב של 4 בייטים לכל אחד מהפריטים שלמעלה. אלה 4 הבייטים הראשונים של הגיבוב המלא בן 32 הבייטים, שמתורגמים כמספרים שלמים של 32 ביט בסדר big-endian. המשמעות של big endian היא שהבייט הראשון של הגיבוב המלא הופך לבייט המשמעותי ביותר של המספר השלם באורך 32 ביט. השלב הזה מניב את המספרים השלמים 0x291bc542,‏ 0x1d32c508 ו-0xf7a502e5.

השרת צריך למיין את שלוש הקידומות האלה של גיבוב לפי סדר אלפביתי (שווה ערך למיון מספרי ב-big endian), ותוצאת המיון היא 0x1d32c508, ‏ 0x291bc542, ‏ 0xf7a502e5. הקידומת הראשונה של הגיבוב נשמרת ללא שינוי בשדה first_value.

לאחר מכן, השרת מחשב את שני ההפרשים הסמוכים, שהם 0xbe9003a ו-0xce893da3 בהתאמה. מאחר ש-k נבחר כ-30, השרת מחלק את שני המספרים האלה לחלקי החולקה ולחלקי השארית באורך 2 ו-30 ביט, בהתאמה. במספר הראשון, חלק המכפיל הוא אפס והיתרה היא 0xbe9003a. במספר השני, חלק המכפיל הוא 3 כי שתי הסיביות המשמעותיות ביותר הן 11 בספרות בינאריות והיתרה היא 0xe893da3. עבור סכום נתון q, הוא מקודד ל-(1 << q) - 1 באמצעות בדיוק 1 + q ביט; השארית מקודדת ישירות באמצעות k ביט. החלק של החולקה במספר הראשון מקודד כ-0, והחלק של השארית הוא 001011111010010000000000111010 בספרות בינאריות. החלק של החולקה במספר השני מקודד כ-0111, והחלק של השארית הוא 001110100010010011110110100011.

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

001110100010010011110110100011 # Second number, remainder part
0111 # Second number, quotient part
001011111010010000000000111010 # First number, remainder part
0 # First number, quotient part

כאשר כותבים את זה בשורה אחת, זה נראה כך:

00111010001001001111011010001101110010111110100100000000001110100

כמובן שהמספר הזה חורג בהרבה מ-8 הביטים שזמינים בבייט אחד. לאחר מכן, קידוד little endian לוקח את 8 הסיביות הפחות משמעותיות במספר הזה, ומפיק אותן כבייט הראשון, שהוא 01110100. לשם הבהרה, אפשר לקבץ את מחרוזת הביטים שלמעלה לקבוצות של שמונה, החל מהביטים המשמעותיים פחות:

0 01110100 01001001 11101101 00011011 10010111 11010010 00000000 01110100

לאחר מכן, קידוד little endian לוקח כל בייט מהצד הימני ומכניס אותו למחרוזת בייטים:

01110100
00000000
11010010
10010111
00011011
11101101
01001001
01110100
00000000

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

זה מוביל בסופו של דבר לכך

additions_four_bytes {
  first_value: 489866504
  rice_parameter: 30
  entries_count: 2
  encoded_data: "t\000\322\227\033\355It\000"
}

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

פענוח של אינדקסים של הסרות

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

תדירות עדכון

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