כתובות URL וגיבוב (hashing)

המסמך הזה רלוונטי לשיטה הבאה: Update API (גרסה 4): fullHashes.find.

סקירה כללית

הרשימות של הגלישה הבטוחה מורכבות מגיבובים (hash) של SHA256 באורך משתנה (ראו תוכן הרשימות). כדי לבדוק כתובת URL מול רשימת גלישה בטוחה (באופן מקומי או בשרת), הלקוחות צריכים קודם מחשבים את תחילית הגיבוב של כתובת ה-URL הזו.

כדי לחשב את לפני הגיבוב של כתובת URL, יש לפעול לפי השלבים הבאים:

  1. להפוך את כתובת ה-URL לקנונית (ראו קנוניזציה).
  2. יצירת ביטויים של הסיומת/הקידומת של כתובת ה-URL (מידע נוסף זמין בקטע ביטויי סיומות/קידומת).
  3. מחשבים את גיבוב האורך המלא של כל ביטוי סיומת/תחילית (ראו חישובי גיבוב).
  4. מחשבים את התחילית של הגיבוב לכל גיבוב באורך מלא (ראו חישובי תחיליות של גיבוב).

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

קנוניזציה

קודם כל, אנחנו מניחים שהלקוח ניתח את כתובת ה-URL והפך אותה לתקינה בהתאם לתקן RFC 2396. אם בכתובת ה-URL נעשה שימוש בשם דומיין בינלאומי (IDN), הלקוח צריך להמיר את כתובת ה-URL לייצוג ASCII Punycode. כתובת ה-URL חייבת לכלול רכיב נתיב. כלומר, חייבת להיות לו קו נטוי בסוף ("http://google.com/ ").

קודם כול, מסירים את תווי Tab (0x09), CR (0x0d) ו-LF (0x0a) מ- כתובת ה-URL. אין להסיר רצפי בריחה עבור התווים האלה (למשל %0a).

שנית, אם כתובת ה-URL מסתיימת במקטע, צריך להסיר את המקטע. לדוגמה, מקצרים את הכתובת ‎http://google.com/#frag‎ לכתובת ‎http://google.com/‎.

שלישית, ביטול בריחה של כתובת ה-URL באמצעות אחוזים חוזרים, עד שלא יהיו לה יותר תווי בריחה (escape).

כדי להפוך את שם המארח לקנוני:

מחלצים את שם המארח מכתובת ה-URL ואז:

  1. מסירים את כל הנקודות המובילות והסופיות.
  2. מחליפים נקודות ברצף בנקודה אחת.
  3. אם אפשר לנתח את שם המארח ככתובת IP, צריך לנרמל אותו ל-4 ערכים עשרוניים מופרדים בנקודות. הלקוח צריך לטפל בכל קידוד חוקי של כתובת IP, כולל אוקטלי, הקסדצימלי ופחות מארבעה רכיבים.
  4. צריך להשתמש באותיות קטנות בכל המחרוזת.

כדי לקבוע את הנתיב כגרסה הרשמית (הקנונית):

  1. פותרים את הרצפים ‎"‎/../" ו-‎"‎/./"‎‎ בנתיב על ידי החלפת ‎"‎/./"‎‎ ב-‎"‎/"‎‎ והסרת ‎"‎/../"‎‎ יחד עם רכיב הנתיב הקודם.
  2. החלפת מחרוזות של קווים נטויים רצופים בתו קו נטוי יחיד.

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

בכתובת ה-URL, בוחרים בתו בריחה (escape) באחוזים את כל התווים שהם <= ASCII 32, >= 127, '#' או '%'. תווי הבריחה (escape) צריכים להיות תווים הקסדצימליים באותיות רישיות.

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

Canonicalize("http://host/%25%32%35") = "http://host/%25";
Canonicalize("http://host/%25%32%35%25%32%35") = "http://host/%25%25";
Canonicalize("http://host/%2525252525252525") = "http://host/%25";
Canonicalize("http://host/asdf%25%32%35asd") = "http://host/asdf%25asd";
Canonicalize("http://host/%%%25%32%35asd%%") = "http://host/%25%25%25asd%25%25";
Canonicalize("http://www.google.com/") = "http://www.google.com/";
Canonicalize("http://%31%36%38%2e%31%38%38%2e%39%39%2e%32%36/%2E%73%65%63%75%72%65/%77%77%77%2E%65%62%61%79%2E%63%6F%6D/") = "http://168.188.99.26/.secure/www.ebay.com/";
Canonicalize("http://195.127.0.11/uploads/%20%20%20%20/.verify/.eBaysecure=updateuserdataxplimnbqmn-xplmvalidateinfoswqpcmlx=hgplmcx/") = "http://195.127.0.11/uploads/%20%20%20%20/.verify/.eBaysecure=updateuserdataxplimnbqmn-xplmvalidateinfoswqpcmlx=hgplmcx/";
Canonicalize("http://host%23.com/%257Ea%2521b%2540c%2523d%2524e%25f%255E00%252611%252A22%252833%252944_55%252B") = "http://host%23.com/~a!b@c%23d$e%25f^00&11*22(33)44_55+";
Canonicalize("http://3279880203/blah") = "http://195.127.0.11/blah";
Canonicalize("http://www.google.com/blah/..") = "http://www.google.com/";
Canonicalize("www.google.com/") = "http://www.google.com/";
Canonicalize("www.google.com") = "http://www.google.com/";
Canonicalize("http://www.evil.com/blah#frag") = "http://www.evil.com/blah";
Canonicalize("http://www.GOOgle.com/") = "http://www.google.com/";
Canonicalize("http://www.google.com.../") = "http://www.google.com/";
Canonicalize("http://www.google.com/foo\tbar\rbaz\n2") ="http://www.google.com/foobarbaz2";
Canonicalize("http://www.google.com/q?") = "http://www.google.com/q?";
Canonicalize("http://www.google.com/q?r?") = "http://www.google.com/q?r?";
Canonicalize("http://www.google.com/q?r?s") = "http://www.google.com/q?r?s";
Canonicalize("http://evil.com/foo#bar#baz") = "http://evil.com/foo";
Canonicalize("http://evil.com/foo;") = "http://evil.com/foo;";
Canonicalize("http://evil.com/foo?bar;") = "http://evil.com/foo?bar;";
Canonicalize("http://\x01\x80.com/") = "http://%01%80.com/";
Canonicalize("http://notrailingslash.com") = "http://notrailingslash.com/";
Canonicalize("http://www.gotaport.com:1234/") = "http://www.gotaport.com/";
Canonicalize("  http://www.google.com/  ") = "http://www.google.com/";
Canonicalize("http:// leadingspace.com/") = "http://%20leadingspace.com/";
Canonicalize("http://%20leadingspace.com/") = "http://%20leadingspace.com/";
Canonicalize("%20leadingspace.com/") = "http://%20leadingspace.com/";
Canonicalize("https://www.securesite.com/") = "https://www.securesite.com/";
Canonicalize("http://host.com/ab%23cd") = "http://host.com/ab%23cd";
Canonicalize("http://host.com//twoslashes?more//slashes") = "http://host.com/twoslashes?more//slashes";

ביטויים של סיומת/קידומת

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

ביטוי קידומת/סיומתביטוי רגולרי שווה ערך
a.b/mypath/
http\:\/\/.*\.a\.b\/mypath\/.*
c.d/full/path.html?myparam=a
http\:\/\/.*.c\.d\/full\/path\.html?myparam=a

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

במקרה של המארח, הלקוח ינסה עד חמש מחרוזות שונות. סוגי המשנה הם:

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

בנתיב, הלקוח ינסה עד שש מחרוזות שונות. הם הן:

  • הנתיב המדויק של כתובת ה-URL, כולל פרמטרים של שאילתה.
  • הנתיב המדויק של כתובת ה-URL, ללא פרמטרים של שאילתה.
  • ארבעת הנתיבים שנוצרו על ידי התחלה בשדה השורש (/) וצירוף הנתיב ברצף כולל קו נטוי בסוף.

הדוגמאות הבאות ממחישות את התנהגות הבדיקה:

עבור כתובת ה-URL http://a.b.c/1/2.html?param=1, הלקוח ינסה את הפעולות הבאות מחרוזות אפשריות:

a.b.c/1/2.html?param=1
a.b.c/1/2.html
a.b.c/
a.b.c/1/
b.c/1/2.html?param=1
b.c/1/2.html
b.c/
b.c/1/

עבור כתובת ה-URL http://a.b.c.d.e.f.g/1.html, הלקוח ינסה את המחרוזות האפשריות הבאות:

a.b.c.d.e.f.g/1.html
a.b.c.d.e.f.g/
(Note: skip b.c.d.e.f.g, since we'll take only the last five hostname components, and the full hostname)
c.d.e.f.g/1.html
c.d.e.f.g/
d.e.f.g/1.html
d.e.f.g/
e.f.g/1.html
e.f.g/
f.g/1.html
f.g/

עבור כתובת ה-URL http://1.2.3.4/1/, הלקוח ינסה את המחרוזות האפשריות הבאות:

1.2.3.4/1/
1.2.3.4/

חישובי גיבוב (hash)

אחרי שיוצרים את קבוצת הביטויים של הסיומת/התחילית, השלב הבא הוא לחשב את הגיבוב (hash) של SHA256 באורך מלא לכל ביטוי. בהמשך מופיע בדיקת יחידה (ב-pseudo-C) שאפשר להשתמש בה כדי לאמת את חישובי הגיבוב.

דוגמאות מ-FIPS-180-2:

Unit Test (in pseudo-C)

// Example B1 from FIPS-180-2
string input1 = "abc";
string output1 = TruncatedSha256Prefix(input1, 32);
int expected1[] = { 0xba, 0x78, 0x16, 0xbf };
assert(output1.size() == 4);  // 4 bytes == 32 bits
for (int i = 0; i < output1.size(); i++) assert(output1[i] == expected1[i]);

// Example B2 from FIPS-180-2
string input2 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
string output2 = TruncatedSha256Prefix(input2, 48);
int expected2[] = { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06 };
assert(output2.size() == 6);
for (int i = 0; i < output2.size(); i++) assert(output2[i] == expected2[i]);

// Example B3 from FIPS-180-2
string input3(1000000, 'a');  // 'a' repeated a million times
string output3 = TruncatedSha256Prefix(input3, 96);
int expected3[] = { 0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92,
                    0x81, 0xa1, 0xc7, 0xe2 };
assert(output3.size() == 12);
for (int i = 0; i < output3.size(); i++) assert(output3[i] == expected3[i]);

חישובי תחיליות של גיבוב (hash)

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

דוגמאות מ-FIPS-180-2:

  • דוגמה B1 מ-FIPS-180-2
    • הקלט הוא 'abc'.
    • תקציר SHA256 הוא ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad.
    • הקידומת של גיבוב 32 הביט היא ba7816bf.
  • דוגמה B2 מ-FIPS-180-2
    • הקלט הוא "abcdbcdecdefgefghfghighijhijkijkljklmklmnlmnomnopnopq".
    • תקציר SHA256 הוא 248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1.
    • התחילית של גיבוב (hash) של 48 ביט היא 248d6a61 d206.