גיבוב של כתובות URL

סקירה כללית

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

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

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

שימו לב שהשלבים האלה משקפים את התהליך שבו שרת Web Risk משתמש כדי לתחזק את רשימות Web Risk.

קביעת כתובת ה-URL כגרסה הרשמית (הקנונית

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

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

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

שלישית, מסירים שוב ושוב את תווי ה-escape של האחוזים מכתובת ה-URL עד שלא נשארים בה עוד תווי escape של אחוזים.

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

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

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

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

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

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

בכתובת ה-URL, צריך להשתמש בסימן האחוז כדי לבצע escape לכל התווים שהם <= ASCII 32,‏ >= 127,‏ # או %. התווים שמוחלפים צריכים להיות בפורמט הקסדצימלי באותיות רישיות.

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

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 באורך מלא לכל ביטוי. למטה מופיעה בדיקת יחידה ב-pseudo-C שאפשר להשתמש בה כדי לאמת את חישובי הגיבוב.

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

// 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)

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

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

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