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

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

סקירה כללית

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

כדי לחשב את קידומת ה-hash של כתובת אתר, בצע את הצעדים הבאים:

  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. אין להסיר רצפי Escape עבור התווים האלה (למשל '%0a').

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

שלישית, אחוז ביטול escape בכתובת האתר באופן חוזר ונשנה, עד שלא יהיו בה עוד תווי escape.

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

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

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

כדי להגדיר את הנתיב כקנונית:

  1. צריך לפתור את הרצפים '/../' ו-'/./' בנתיב על ידי החלפת '/./' ב-'/' והסרה של '/../' יחד עם רכיב הנתיב הקודם.
  2. החלפת רצפים של לוכסנים רציפים בתו אחד של לוכסן.

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

בכתובת ה-URL, צריך לסמן בכוכב את כל התווים שהם <= 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)

לאחר יצירת קבוצה של ביטויי סיומת/קידומת, השלב הבא הוא חישוב גיבוב SHA256 באורך מלא לכל ביטוי. בהמשך מופיעה בדיקת יחידה (בפסאודו-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 באורך מלא. במצב גלישה בטוחה, קידומת גיבוב (hash) מורכבת מ-4 עד 32 בייטים שהם המשמעותיים ביותר מבחינת גיבוב SHA256.

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

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