URL 및 해싱

이 문서는 다음 메서드에 적용됩니다. Update API (v4): fullHashes.find.

개요

세이프 브라우징 목록은 가변 길이 SHA256 해시로 구성됩니다(목록 콘텐츠 참고). 로컬 또는 서버에서 세이프 브라우징 목록의 URL을 확인하려면 먼저 클라이언트가 해당 URL의 해시 접두사를 계산해야 합니다.

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

  1. URL 표준화 표준화를 참고하세요.
  2. URL의 서픽스/프리픽스 표현식을 만듭니다(서픽스/프리픽스 표현식 참고).
  3. 각 서픽스/프리픽스 표현식의 전체 길이 해시를 계산합니다(해시 계산 참고).
  4. 각 전체 길이 해시의 해시 접두사를 계산합니다(해시 접두사 계산 참고).

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

표준화

먼저 클라이언트가 URL을 파싱하고 RFC 2396에 따라 유효하게 만들었다고 가정합니다. URL에서 국제화된 도메인 이름(IDN)을 사용하는 경우 클라이언트는 URL을 ASCII 퓨니코드 표현으로 변환해야 합니다. URL은 경로 구성요소를 포함해야 합니다. 즉, 맨 뒤의 슬래시('http://google.com/')를 사용합니다.

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

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

셋째, 더 이상 퍼센트 이스케이프 처리를 하지 않을 때까지 URL의 퍼센트 이스케이프 처리를 반복합니다.

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

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

  1. 모든 선행 및 후행 점은 삭제합니다.
  2. 연속된 점을 단일 점으로 바꿉니다.
  3. 호스트 이름을 IP 주소로 파싱할 수 있는 경우 정규화합니다. 4개의 점으로 구분된 십진수 값으로 표시됩니다. 클라이언트는 모든 법적 IP 주소 인코딩을 처리해야 합니다. 8진수, 16진수 및 4개 미만의 구성요소가 포함됩니다.
  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의 정확한 경로입니다.
  • 루트 (/)에서 시작하고 연속적으로 경로를 추가하여 형성된 네 개의 경로 구성요소를 포함할 수 있습니다.

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

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의 경우 클라이언트가 가능한 방법을 시도합니다. strings:

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/의 경우 클라이언트가 가능한 방법을 시도합니다. strings:

1.2.3.4/1/
1.2.3.4/

해시 계산

서픽스/프리픽스 표현식 집합을 만들었으면 다음 단계는 각 표현식의 전체 길이 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]);

해시 프리픽스 계산

마지막으로 클라이언트는 각 전체 길이 SHA256 해시의 해시 접두사를 계산해야 합니다. 안전용 브라우징의 경우 해시 접두사는 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입니다.