Hashing de URLs

Vista geral

As listas do Web Risk consistem em hashes SHA256 de comprimento variável. Para mais detalhes, consulte Conteúdos da lista. Para verificar um URL numa lista do Web Risk, localmente ou no servidor, os clientes têm de calcular primeiro o prefixo de hash desse URL.

Para calcular o prefixo hash de um URL, siga estes passos:

  1. Canonicalize o URL conforme descrito em Canonicalização.
  2. Crie as expressões de sufixo/prefixo para o URL, conforme descrito em Expressões de sufixo/prefixo.
  3. Calcule o hash de comprimento total para cada expressão de sufixo/prefixo conforme descrito em Cálculos de hash.
  4. Calcule o prefixo hash para cada hash de comprimento total, conforme descrito em Cálculos do prefixo hash.

Tenha em atenção que estes passos refletem o processo que o servidor do Web Risk usa para manter as listas do Web Risk.

Canonicalização

Para começar, partimos do princípio de que o cliente analisou o URL e o tornou válido de acordo com a RFC 2396. Se o URL usar um nome de domínio internacionalizado (IDN), o cliente deve converter o URL na representação ASCII Punycode. O URL tem de incluir um componente de caminho, ou seja, tem de ter uma barra inicial (http://google.com/).

Primeiro, remova os carateres de tabulação (0x09), CR (0x0d) e LF (0x0a) do URL. Não remova as sequências de escape destes carateres, como %0a.

Em segundo lugar, se o URL terminar num fragmento, remova o fragmento. Por exemplo, abrevie http://google.com/#frag para http://google.com/.

Em terceiro lugar, remova repetidamente os carateres de escape em percentagem do URL até não ter mais carateres de escape em percentagem.

Para canonicalizar o nome do anfitrião

Extraia o nome do anfitrião do URL e, em seguida:

  1. Remova todos os pontos à esquerda e à direita.
  2. Substitua pontos consecutivos por um único ponto.
  3. Se o nome de anfitrião puder ser analisado como um endereço IP, normalize-o para 4 valores decimais separados por pontos. O cliente deve processar qualquer codificação de endereço IP legal, incluindo octal, hexadecimal e menos de quatro componentes.
  4. Converter toda a string em minúsculas.

Para canonicalizar o caminho

  1. Resolva as sequências /../ e /./ no caminho substituindo /./ por / e removendo /../ juntamente com o componente do caminho anterior.
  2. Substitua sequências de barras consecutivas por um único caráter de barra.

Não aplique estas canonicalizações de caminhos aos parâmetros de consulta.

No URL, escape com percentagem todos os carateres que sejam <= ASCII 32, >= 127, # ou %. As sequências de escape devem usar carateres hexadecimais em maiúsculas.

Seguem-se testes para ajudar a validar uma implementação da canonicalização.

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";

Expressões de sufixo/prefixo

Depois de o URL ser canonicalizado, o passo seguinte é criar as expressões de sufixo/prefixo. Cada expressão de sufixo/prefixo consiste num sufixo de anfitrião (ou anfitrião completo) e num prefixo de caminho (ou caminho completo), conforme mostrado nestes exemplos.

Expressão de sufixo/prefixo Expressão regular equivalente
a.b/mypath/ http\:\/\/.*\.a\.b\/mypath\/.*
c.d/full/path.html?myparam=a http\:\/\/.*.c\.d\/full\/path\.html?myparam=a

O cliente vai formar até 30 combinações possíveis diferentes de sufixo do anfitrião e prefixo do caminho. Estas combinações usam apenas os componentes de anfitrião e caminho do URL. O esquema, o nome de utilizador, a palavra-passe e a porta são ignorados. Se o URL incluir parâmetros de consulta, pelo menos uma combinação vai incluir o caminho completo e os parâmetros de consulta.

Para o anfitrião, o cliente vai experimentar, no máximo, cinco strings diferentes. São eles:

  • O nome do anfitrião exato no URL.
  • Até quatro nomes de anfitrião formados começando pelos últimos cinco componentes e removendo sucessivamente o componente principal. Pode ignorar o domínio de nível superior. Estes nomes de anfitrião adicionais não devem ser verificados se o anfitrião for um endereço IP.

Para o caminho, o cliente vai experimentar, no máximo, seis strings diferentes. São eles:

  • O caminho exato do URL, incluindo os parâmetros de consulta.
  • O caminho exato do URL, sem parâmetros de consulta.
  • Os quatro caminhos formados começando na raiz (/) e acrescentando sucessivamente componentes do caminho, incluindo uma barra.

Os exemplos seguintes ilustram o comportamento da verificação:

Para o URL http://a.b.c/1/2.html?param=1, o cliente vai experimentar estas strings possíveis:

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/

Para o URL http://a.b.c.d.e.f.g/1.html, o cliente vai experimentar estas possíveis 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/

Para o URL http://1.2.3.4/1/, o cliente vai experimentar estas strings possíveis:

1.2.3.4/1/
1.2.3.4/

Cálculos de hash

Depois de criar o conjunto de expressões de sufixo/prefixo, o passo seguinte é calcular o hash SHA256 de comprimento total para cada expressão. Abaixo encontra um teste de unidade em pseudo-C que pode usar para validar os seus cálculos de hash.

Exemplos de 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]);

Cálculos de prefixos hash

Por fim, o cliente tem de calcular o prefixo de hash para cada hash SHA256 de comprimento total. Para o Web Risk, um prefixo de hash consiste nos 4 a 32 bytes mais significativos de um hash SHA256.

Exemplos de FIPS-180-2:

  • Exemplo B1 de FIPS-180-2
    • A entrada é "abc".
    • O resumo SHA256 é ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad.
    • O prefixo hash de 32 bits é ba7816bf.
  • Exemplo B2 da FIPS-180-2
    • A entrada é abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq.
    • O resumo SHA256 é 248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1.
    • O prefixo hash de 48 bits é 248d6a61 d206.