Local Database

La versione 5 di Navigazione sicura di Google si aspetta che il client gestisca un database locale, tranne quando il client sceglie la modalità in tempo reale senza archiviazione. Spetta al cliente il formato e l'archiviazione di questo database locale. I contenuti di questo database locale possono essere concettualmente considerati come una cartella contenente vari elenchi sotto forma di file e i contenuti di questi file sono hash SHA256 o i relativi prefissi corrispondenti, con un prefisso hash di quattro byte che è la lunghezza dell'hash più comunemente utilizzata.

Elenchi disponibili

Gli elenchi sono identificati dai loro nomi distinti che seguono una convenzione di denominazione in cui il nome contiene un suffisso che indica la lunghezza dell'hash che dovresti aspettarti nell'elenco. Gli elenchi di hash con lo stesso tipo di minaccia, ma con una lunghezza dell'hash diversa, saranno un elenco con nome distinto, qualificato con un suffisso che indica la lunghezza dell'hash.

I seguenti elenchi sono disponibili per l'utilizzo con i metodi degli elenchi di hash.

Nome elenco Enum ThreatType v4 corrispondente Descrizione
gc-32b Nessuno Questo è un elenco della cache globale. Si tratta di un elenco speciale utilizzato solo nella modalità di funzionamento in tempo reale.
se-4b SOCIAL_ENGINEERING Questo elenco contiene minacce di tipo SOCIAL_ENGINEERING.
mw-4b MALWARE Questo elenco contiene minacce del tipo MALWARE per le piattaforme desktop.
uws-4b UNWANTED_SOFTWARE Questo elenco contiene minacce del tipo UNWANTED_SOFTWARE per le piattaforme desktop.
uwsa-4b UNWANTED_SOFTWARE Questo elenco contiene minacce del tipo UNWANTED_SOFTWARE per le piattaforme Android.
pha-4b POTENTIALLY_HARMFUL_APPLICATION Questo elenco contiene minacce del tipo POTENTIALLY_HARMFUL_APPLICATION per le piattaforme Android.

Altri elenchi possono diventare disponibili in un secondo momento, a quel punto la tabella sopra riportata verrà espansa e i risultati del metodo hashList.list mostreranno un risultato simile con gli elenchi più aggiornati.

Aggiornamenti del database

Il client chiamerà regolarmente il metodo hashList.get o il metodo hashLists.batchGet per aggiornare il database. Poiché il cliente tipico vorrà aggiornare più elenchi contemporaneamente, è consigliabile utilizzare il metodo hashLists.batchGet.

I nomi degli elenchi non verranno mai rinominati. Inoltre, una volta visualizzato, un elenco non verrà mai rimosso (se non è più utile, diventerà vuoto, ma continuerà a esistere). Pertanto, è opportuno codificare questi nomi nel codice client di Google Navigazione sicura.

Sia il metodo hashList.get sia il metodo hashLists.batchGet supportano gli aggiornamenti incrementali. L'utilizzo di aggiornamenti incrementali consente di risparmiare larghezza di banda e migliorare le prestazioni. Gli aggiornamenti incrementali funzionano generando un delta tra la versione dell'elenco del client e la versione più recente dell'elenco. Se un client è stato appena disegnato e non ha versioni disponibili, è disponibile un aggiornamento completo. L'aggiornamento incrementale contiene indici di rimozione e aggiunte. Innanzitutto, il cliente deve rimuovere le voci agli indici specificati dal proprio database locale e poi applicare le aggiunte.

Infine, per evitare la corruzione, il client deve verificare i dati archiviati rispetto al checksum fornito dal server. Ogni volta che il checksum non corrisponde, il client deve eseguire un aggiornamento completo.

Decodifica dei contenuti dell'elenco

Decodifica di hash e prefissi di hash

Tutti gli elenchi vengono pubblicati utilizzando una codifica speciale per ridurre le dimensioni. Questa codifica funziona riconoscendo che gli elenchi di Navigazione sicura di Google contengono, concettualmente, un insieme di hash o prefissi di hash, che sono statisticamente indistinguibili da numeri interi casuali. Se dovessimo ordinare questi numeri interi e prendere la loro differenza adiacente, questa differenza adiacente dovrebbe essere "piccola" in un certo senso. La codifica Golomb-Rice sfrutta questa ridotta dimensione.

Supponiamo che tre espressioni di prefisso del percorso con suffisso host, ovvero a.example.com/, b.example.com/ e y.example.com/, debbano essere trasmesse utilizzando preffissi hash di 4 byte. Supponiamo inoltre che il parametro di Rice, indicato con k, sia scelto in modo che

  1. Il server inizierà calcolando l'hash completo di queste stringhe, che sono rispettivamente:
291bc5421f1cd54d99afcc55d166e2b9fe42447025895bf09dd41b2110a687dc  a.example.com/
1d32c5084a360e58f1b87109637a6810acad97a861a7769e8f1841410d2a960c  b.example.com/
f7a502e56e8b01c6dc242b35122683c9d25d07fb1f532d9853eb0ef3ff334f03  y.example.com/

Il server forma quindi prefissi di hash di 4 byte per ciascuno dei valori precedenti, ovvero i primi 4 byte dell'hash completo di 32 byte, interpretati come numeri interi a 32 bit big-endian. L'ordine big endian si riferisce al fatto che il primo byte dell'hash completo diventa il byte più significativo dell'intero a 32 bit. Questo passaggio genera i numeri interi 0x291bc542, 0x1d32c508 e 0xf7a502e5.

È necessario che il server ordini questi tre prefissi di hash in ordine alfabetico (equivalente all'ordinamento numerico in big endian) e il risultato dell'ordinamento è 0x1d32c508, 0x291bc542, 0xf7a502e5. Il primo prefisso dell'hash viene memorizzato invariato nel campo first_value.

Il server calcola quindi le due differenze adiacenti, che sono rispettivamente 0xbe9003a e 0xce893da3. Dato che k è scelto come 30, il server suddivide questi due numeri nelle parti del quoziente e del resto che hanno rispettivamente 2 e 30 bit di lunghezza. Per il primo numero, la parte del quoziente è zero e il resto è 0xbe9003a; per il secondo numero, la parte del quoziente è 3 perché i due bit più significativi sono 11 in binario e il resto è 0xe893da3. Per un determinato quoziente q, viene codificato in (1 << q) - 1 utilizzando esattamente 1 + q bit; il resto viene codificato direttamente utilizzando k bit. La parte del quoziente del primo numero è codificata come 0 e la parte del resto è in binario 001011111010010000000000111010; la parte del quoziente del secondo numero è codificata come 0111 e la parte del resto è 001110100010010011110110100011.

Quando questi numeri vengono formattati in una stringa di byte, viene utilizzato il little endian. Concettualmente, può essere più facile immaginare una lunga stringa di bit formata a partire dai bit meno significativi: prendiamo la parte del quoziente del primo numero e anteponiamo la parte del resto del primo numero; poi anteponiamo ulteriormente la parte del quoziente del secondo numero e la parte del resto. Dovresti ottenere il seguente numero elevato (interruzioni di riga e commenti aggiunti per chiarezza):

001110100010010011110110100011 # Second number, remainder part
0111 # Second number, quotient part
001011111010010000000000111010 # First number, remainder part
0 # First number, quotient part

Se scritto in una sola riga, il codice sarà

00111010001001001111011010001101110010111110100100000000001110100

Ovviamente questo numero supera di gran lunga gli 8 bit disponibili in un singolo byte. La codifica little endian prende quindi gli 8 bit meno significativi del numero e li restituisce come primo byte, ovvero 01110100. Per chiarezza, possiamo raggruppare la stringa di bit sopra in gruppi di otto a partire dai bit meno significativi:

0 01110100 01001001 11101101 00011011 10010111 11010010 00000000 01110100

La codifica little endian prende quindi ogni byte da destra e lo inserisce in una stringa di byte:

01110100
00000000
11010010
10010111
00011011
11101101
01001001
01110100
00000000

Poiché concettualmente anteponiamo nuove parti al numero grande a sinistra (ovvero aggiungiamo bit più significativi), ma codifichiamo da destra (ovvero dai bit meno significativi), la codifica e la decodifica possono essere eseguite in modo incrementale.

Il risultato finale è

additions_four_bytes {
  first_value: 489866504
  rice_parameter: 30
  entries_count: 2
  encoded_data: "t\000\322\227\033\355It\000"
}

Il client segue semplicemente i passaggi precedenti in ordine inverso per decodificare i prefissi degli hash.

Indici di rimozione della decodifica

Gli indici di rimozione vengono codificati utilizzando la stessa tecnica di cui sopra, con numeri interi a 32 bit.

Frequenza degli aggiornamenti

Il client deve ispezionare il valore restituito dal server nel campo minimum_wait_duration e utilizzarlo per pianificare il successivo aggiornamento del database. Questo valore potrebbe essere zero (il campo minimum_wait_duration è completamente mancante), nel qual caso il client DEVE eseguire immediatamente un altro aggiornamento.