해싱 URL

개요

Web Risk 목록은 가변 길이 SHA256 해시로 구성됩니다. 자세한 내용은 목록 콘텐츠를 참조하세요. 로컬 또는 서버에서 Web Risk 목록의 URL을 확인하려면 먼저 클라이언트가 해당 URL의 해시 프리픽스를 계산해야 합니다.

URL의 해시 프리픽스를 계산하려면 다음 안내를 따르세요.

  1. 표준화에 설명한 URL을 표준화합니다.
  2. 서픽스/프리픽스 표현식에 설명된 대로 URL의 서픽스/프리픽스 표현식을 만듭니다.
  3. 해시 계산에 설명된 대로 각 서픽스/프리픽스 표현식의 전체 길이 해시를 계산합니다.
  4. 해시 프리픽스 계산에 설명된 대로 각 전체 길이 해시의 해시 프리픽스를 계산합니다.

이 단계는Web Risk 서버가 Web Risk 목록을 유지하는 데 사용하는 프로세스를 반영합니다.

표준화

먼저 클라이언트가 파싱한 URL이 RFC 2396에 따라 유효하다고 가정합니다. URL에서 국제화된 도메인 이름(IDN)을 사용하는 경우 클라이언트는 URL을 ASCII Punycode 표현으로 변환해야 합니다. URL에는 경로 구성요소가 포함되어야 합니다. 즉, 선행 슬래시(http://google.com/)가 있어야 합니다.

먼저 URL에서 탭(0x09), CR(0x0d), LF(0x0a) 문자를 삭제합니다. %0a와 같이 이러한 문자는 이스케이프 시퀀스를 제거하지 마세요.

둘째, URL이 프래그먼트로 끝나면 프래그먼트를 제거합니다. 예를 들어 http://google.com/#fraghttp://google.com/로 줄입니다.

세 번째로, URL에서 더 이상 퍼센트 이스케이프 문자가 남지 않을 때까지 퍼센트 이스케이프 문자를 반복적으로 삭제합니다.

호스트 이름을 표준화하려면 다음 안내를 따르세요.

URL에서 호스트 이름을 추출한 후 다음을 수행합니다.

  1. 모든 선행 및 후행 점은 삭제합니다.
  2. 연속된 점을 단일 점으로 바꿉니다.
  3. 호스트 이름을 IP 주소로 파싱할 수 있는 경우 4개의 점으로 구분된 십진수 값으로 정규화합니다. 클라이언트는 8진수, 16진수, 4개 미만의 구성 요소를 포함한 모든 법적 IP 주소 인코딩을 처리해야 합니다.
  4. 전체 문자열을 소문자로 표기합니다.

경로를 표준화하려면 다음 안내를 따르세요.

  1. /.//로 바꾸고 이전 경로 구성요소와 함께 /../를 삭제하여 경로의 /..//./ 시퀀스를 확인합니다.
  2. 연속된 슬래시 실행을 단일 슬래시 문자로 바꿉니다.

이러한 경로 표준화를 쿼리 매개변수에 적용하지 마세요.

URL에서 <= ASCII 32, >= 127, # 또는 %인 모든 문자를 퍼센트 문자로 이스케이프 처리합니다. 이스케이프는 대문자 16진수를 사용해야합니다.

다음은 표준화 구현을 검증하는 데 도움이 되는 테스트입니다.

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에 쿼리 매개변수가 포함된 경우에는 하나 이상의 조합에 전체 경로 및 쿼리 매개변수가 포함됩니다.

호스트의 경우 클라이언트는 최대 5개의 다른 문자열을 시도합니다. 문자열은 다음과 같습니다.

  • URL의 정확한 호스트 이름입니다.
  • 마지막 5개 구성요소로 시작하고 앞의 구성요소를 연속적으로 삭제하여 최대 4개의 호스트 이름을 만듭니다. 최상위 도메인의 경우 건너뛸 수 있습니다. 호스트가 IP 주소인 경우 이러한 추가 호스트 이름을 확인하면 안 됩니다.

경로의 경우 클라이언트는 최대 6개의 다른 문자열을 시도합니다. 문자열은 다음과 같습니다.

  • 쿼리 매개변수를 포함한 URL의 정확한 경로입니다.
  • 쿼리 매개변수가 없는 URL의 정확한 경로입니다.
  • 루트(/)에서 시작하여 후행 슬래시를 포함하여 경로 구성 요소를 연속적으로 추가하여 형성되는 4개의 경로입니다.

다음 예시는 확인 동작을 보여줍니다.

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/

해시 계산

서픽스/프리픽스 표현식 집합을 만들어지면 다음으로 각 표현식의 전체 길이 SHA256 해시를 계산합니다. 다음은 의사 코드(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]);

해시 프리픽스 계산

마지막으로 클라이언트는 각 전체 길이 SHA256 해시의 해시 프리픽스를 계산해야 합니다. Web Risk의 경우 해시 프리픽스는 SHA256 해시의 최상위 4-32 바이트로 구성됩니다.

FIPS-180-2의 예시:

  • FIPS-180-2의 B1 예시
    • 입력은 'abc'입니다.
    • SHA256 다이제스트는 ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad입니다.
    • 32비트 해시 프리픽스는 ba7816bf입니다.
  • FIPS-180-2의 B2 예시
    • 입력은 abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq입니다.
    • SHA256 다이제스트는 248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1입니다.
    • 48비트 해시 프리픽스는 248d6a61 d206입니다.