Local Database

Google Safe Browsing v5 ожидает, что клиент будет поддерживать локальную базу данных, за исключением случаев, когда клиент выбирает режим реального времени без сохранения . Формат и хранение этой локальной базы данных зависят от клиента. Содержимое этой локальной базы данных можно концептуально рассматривать как папку, содержащую различные списки в виде файлов, а содержимое этих файлов представляет собой хэши SHA256 или соответствующие им префиксы, причем наиболее часто используемой длиной хеша является префикс хэша в четыре байта.

Доступные списки

Списки идентифицируются по их отдельным именам, которые следуют соглашению об именовании, где имя содержит суффикс, который обозначает длину хеша, который следует ожидать в списке. Списки хешей с одинаковым типом угрозы, но разной длиной хеша будут иметь отдельное название, которое квалифицировано суффиксом, который обозначает длину хеша.

Следующие списки доступны для использования с методами хэш-списка.

Имя списка Соответствующий v4 ThreatType Enum Описание
gc-32b Никто Этот список является списком глобального кэша. Это специальный список, используемый только в режиме реального времени.
se-4b SOCIAL_ENGINEERING В этом списке содержатся угрозы типа SOCIAL_ENGINEERING.
mw-4b MALWARE В этом списке содержатся угрозы типа MALWARE для настольных платформ.
uws-4b UNWANTED_SOFTWARE В этом списке содержатся угрозы типа UNWANTED_SOFTWARE для настольных платформ.
uwsa-4b UNWANTED_SOFTWARE В этом списке содержатся угрозы типа UNWANTED_SOFTWARE для платформ Android.
pha-4b POTENTIALLY_HARMFUL_APPLICATION В этом списке содержатся угрозы типа ПОТЕНЦИАЛЬНО_ВРЕДНОЕ_ПРИЛОЖЕНИЕ для платформ Android.

Дополнительные списки могут стать доступны позднее, и тогда приведенная выше таблица будет расширена, а результаты метода hashList.list покажут аналогичный результат с самыми актуальными списками.

Обновления базы данных

Клиент будет регулярно вызывать метод hashList.get или метод hashLists.batchGet для обновления базы данных. Поскольку типичный клиент захочет обновить несколько списков одновременно, рекомендуется использовать метод hashLists.batchGet .

Имена списков никогда не будут переименованы. Более того, как только список появился, он никогда не будет удален (если список больше не нужен, он станет пустым, но продолжит существовать). Поэтому целесообразно жестко закодировать эти имена в клиентском коде Google Safe Browsing.

Метод hashList.get и метод hashLists.batchGet поддерживают инкрементные обновления. Использование инкрементных обновлений экономит пропускную способность и повышает производительность. Инкрементные обновления работают, предоставляя разницу между версией списка клиента и последней версией списка. (Если клиент недавно развернут и не имеет доступных версий, доступно полное обновление.) Инкрементное обновление содержит индексы удаления и добавления. Клиент должен сначала удалить записи по указанным индексам из своей локальной базы данных, а затем применить дополнения.

Наконец, чтобы предотвратить повреждение, клиент должен проверить сохраненные данные по контрольной сумме, предоставленной сервером. Всякий раз, когда контрольная сумма не совпадает, клиент должен выполнить полное обновление.

Расшифровка содержания списка

Расшифровка хешей и хеш-префиксов

Все списки доставляются с использованием специальной кодировки для уменьшения размера. Эта кодировка работает, распознавая, что списки Google Safe Browsing содержат, концептуально, набор хэшей или префиксов хэшей, которые статистически неотличимы от случайных целых чисел. Если бы мы отсортировали эти целые числа и взяли их смежную разность, то такая смежная разность, как ожидается, будет «малой» в некотором смысле. Затем кодировка Голомба-Райса использует эту малость.

Предположим, что три выражения host-suffix path-prefix, а именно a.example.com/ , b.example.com/ и y.example.com/ , должны быть переданы с использованием 4-байтовых хэш-префиксов. Далее предположим, что параметр Райса, обозначенный как k, выбран равным

  1. Сервер начнет с вычисления полного хеша для этих строк, которые, соответственно, следующие:
291bc5421f1cd54d99afcc55d166e2b9fe42447025895bf09dd41b2110a687dc  a.example.com/
1d32c5084a360e58f1b87109637a6810acad97a861a7769e8f1841410d2a960c  b.example.com/
f7a502e56e8b01c6dc242b35122683c9d25d07fb1f532d9853eb0ef3ff334f03  y.example.com/

Затем сервер формирует 4-байтовые хэш-префиксы для каждого из вышеперечисленных, которые являются первыми 4 байтами 32-байтового полного хэша, интерпретируемыми как 32-битные целые числа с обратным порядком байтов. Под обратным порядком байтов понимается тот факт, что первый байт полного хэша становится самым значимым байтом 32-битного целого числа. Этот шаг приводит к целым числам 0x291bc542, 0x1d32c508 и 0xf7a502e5.

Серверу необходимо отсортировать эти три хэш-префикса лексикографически (эквивалентно числовой сортировке в big endian), и результат сортировки будет 0x1d32c508, 0x291bc542, 0xf7a502e5. Первый хэш-префикс сохраняется без изменений в поле first_value .

Затем сервер вычисляет две смежные разности, которые равны 0xbe9003a и 0xce893da3 соответственно. Учитывая, что k выбрано равным 30, сервер разбивает эти два числа на частное и остаток длиной 2 и 30 бит соответственно. Для первого числа частное равно нулю, а остаток равен 0xbe9003a; для второго числа частное равно 3, поскольку старшие два бита равны 11 в двоичной системе, а остаток равен 0xe893da3. Для заданного частного q оно кодируется в (1 << q) - 1 используя ровно 1 + q бит; остаток кодируется напрямую, используя k бит. Частное первого числа кодируется как 0, а остаточная часть в двоичной системе счисления — 001011111010010000000000111010; частное второго числа кодируется как 0111, а остаточная часть — 001110100010010011110110100011.

Когда эти числа формируются в строку байтов, используется little endian. Концептуально может быть проще представить, что длинная битовая строка формируется, начиная с наименее значимых битов: мы берем частную часть первого числа и добавляем к ней остаток первого числа; затем мы добавляем к ней частную часть второго числа и добавляем к ней остаток. Это должно привести к следующему большому числу (разрывы строк и комментарии добавлены для ясности):

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

Если написать это в одну строку, то это будет выглядеть так:

00111010001001001111011010001101110010111110100100000000001110100

Очевидно, что это число намного превышает 8 бит, доступных в одном байте. Затем кодирование little endian берет наименее значимые 8 бит в этом числе и выводит их как первый байт, который равен 01110100. Для ясности мы можем сгруппировать приведенную выше битовую строку в группы по восемь, начиная с наименее значимых бит:

0 01110100 01001001 11101101 00011011 10010111 11010010 00000000 01110100

Затем кодировка с прямым порядком байтов берет каждый байт справа и помещает его в строку байтов:

01110100
00000000
11010010
10010111
00011011
11101101
01001001
01110100
00000000

Видно, что поскольку мы концептуально добавляем новые части к большему числу слева (т.е. добавляем более значимые биты), но кодируем справа (т.е. наименее значимые биты), кодирование и декодирование можно выполнять постепенно.

Это в конечном итоге приводит к

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

Клиент просто выполняет вышеуказанные шаги в обратном порядке, чтобы расшифровать префиксы хэша.

Индексы удаления декодирования

Индексы удаления кодируются с использованием точно такой же техники, как и выше, с использованием 32-битных целых чисел.

Частота обновления

Клиент должен проверить возвращаемое сервером значение в поле minimum_wait_duration и использовать его для планирования следующего обновления базы данных. Это значение может быть равно нулю (поле minimum_wait_duration полностью отсутствует), в этом случае клиент ДОЛЖЕН немедленно выполнить еще одно обновление.