Русский
Русский
English
Статистика
Реклама

UUID и браузеры. Почему фронтенд живет без страшных айдишников?

Решил я делать свой пет-проект по учету прочитанных книг на PWA. Покорять новые технологии и все такое. Расчет был на то, что с его выложу и установлю на телефон и вот у меня есть мобильное приложение, которое можно использовать оффлайн. Хочу я сгенерировать UUID, чтобы сохранить книгу, а не нахожу API. Предлагаю разобраться почему.


Что такое UUID


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


UUID представляет собой 16-байтное число в HEX'е формате:


xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx


Где:


x - [0 - f] (Закодированные данные)M - [0 - 5] (Версия UUID)N - [8 - b] (Вариант UUID)

Здесь я не буду вдаваться в подробности, что из этого что означает. С этим вы подробно можете ознакомиться в википедии.


Способы генерации UUID



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


1 и 2 версии использовали время с точностью до 0.1 микросекунды + MAC адрес, что гарантировало практически полное отсутствие возможности получить дубликат. Чтобы полностью добить эту вероятность первая версия добавляет рандомную соль, а вторая ничего не делает (вторую версию мы не любим, она вообще может сгенерировать только 64 уникальных id за семь минут).


3 и 5 хешируют пространство имен (Url, FQDN, OID) + само имя. Таким образом в каждый момент времени мы получаем абсолютно идентичные UUID для одних и тех же входных параметров.


Отличие 3 и 5 версии только в том, что 3 использует для хеширования MD-5, а 5 SHA-1.

4 же версия просто использует рандом _()_/.


Почему его нет в браузере


JS не имеет доступа к данным машины


Мы не можем получить MAC-адрес пользователя, мы не можем получить данные его IP, а так же вообще что-либо с его машины без разрешения пользователя.
Да, мы можем загружать фалы и делать красивые file-инпуты на фронте, но мы можем получить только конкретный файл, который нам предоставит пользователь. Но согласитесь, как бы не шибко удобно запрашивать на каждый UUID по файлу. Неудобно их запрашивать даже каждый раз при входе на сайт.
Сделано же это из благих целей: представьте, что читаете вы Хабр, а тут:



import * as console from 'console';console.run('rm -rf /**/kursach*final-(\d+)?.docx')

И больше никаких проблем с высшим образованием.


Потому что до не давних пор он был просто не нужен


Браузер для того, чтобы сидеть в интернете.
Через браузер мы заходим на сайт. Если мы зашли на сайт нам отдали страничку. А раз нам ее отдали значит мы связаны с сетевым узлом который может сгеерировать UUID и сами мы можем этого не делать. По факту, нам как фронту вообще на ID информации все равно, мы отдали, а дальше это уже проблема принимащей стороны.


Вы можете возразить, что есть PWA, и что оно есть аж с 2007 года. Но так уж вышло, что PWA никому не нужен, примерно, с того же самого времени. (Хотя нынче Play Market позволяет загружать PWA как приложения, но...). Сами посудите, много вы PWA приложений установили? Я даже Хабр не поставил.


Другой вопрос почему до сих тор нет никакого API типа getUUID(), чтобы переложить эту проблему на браузер? Скорее всего ответ кроется все в той же ссылке на то, что в 99 случаев из 100 сайту это просто-напросто незачем.


Но осадочек остался.


Какие трудности вас ждут


Точность времени


Я бы не стал называть это большой проблемой.


Мы можем получить время с точностью только до миллисекунды, в то время как первая версия UUID делала это с точностью до 100 наносекунд.


Ну чисто теоретически мы можем получить и с точностью до 1 микросекунды, но это будет время от открытия вкладки (это если мы сейчас про performance.now()), что уже не так заманчиво.


Идентификация браузера


Браузеры вообще не уникальны и сейчас я вам это докажу.


Для идентификации клиента HTML Living Standard нам предлагает использовать The Navigator object.


А теперь внимание сравним то, что нам предлагают сравнивать


Браузер appCodeName appName platform product productSub vendor vendorSub
Chrome Mozilla Netscape Win32 Gecko 20030107 Google Inc. -
Mozilla 75 Mozilla Netscape Win32 Gecko 20100101 - -
Mozilla 45 Mozilla Netscape Win32 Gecko 20100101 - -
Internet Explorer Mozilla Netscape Win32 Gecko - - -
Microsoft Edge Mozilla Netscape Win32 Gecko 20030107 Google Inc. -

Как вам такое? Почувствовали все разнообразие клиентов? Вот и я нет.


Но радо признать, что местами отличаются userAgent и appVersion:


Браузер appVersion userAgent
Chrome 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36
Mozilla 75 5.0 (Windows) Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0
Mozilla 45 5.0 (Windows) Mozilla/5.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0
Internet Explorer 5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; Tablet PC 2.0; Zoom 3.6.0; rv:11.0) like Gecko Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; Tablet PC 2.0; Zoom 3.6.0; rv:11.0) like Gecko
Microsoft Edge 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36 Edg/88.0.705.74 Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.182 Safari/537.36 Edg/88.0.705.74

Тут Edge впереди планеты всей, так как он отображает IP, и мы можем использовать его. Но это только в Edge. А так, как видите, многого с навигатором не навоюешь.


Как это реализовал я



Для себя я решил отталкиваться от своих нужд и особенностей архитектуры своего приложения.


  1. Книги очень сложно добавлять несколько раз в миллисекунду. Даже просто тыкать на кнопочку сложно.
  2. Книги может добавлять только авторизованный пользователь.

Я первые 6 байт из 16 отвел под миллисекунды timestamp'а, что дает нам возможность генерировать ключи аж до 10889-08-02Т10:31:50.655. Хватит с запасом.


Последние 6 байт я беру из SHA-1 хеша логина можно идентифицировать 281,474,976,710,656 уникальных пользователей (если взять расчет на то, что не будет коллизий). Тоже с запасом (у меня их всего 30).


1 байт у нас отводится на версию (M) и вариант (N).


Оставшиеся 3 байта я солю рандомом.


Что в итоге:


Если вдруг мое приложение станет супер-пупер популярным и 100,000 и они будут за минуту каждый делать по 100 книг, то за миллисекунду будет генерироваться:


$$
100,000 * 100 / 60,000 = 166
$$


Вероятность того, что совпадут два:


$$
166 1/256^3 1/256^5 = 166 1/255^8 = 166 / 18 10^{18}
$$


Это очень мало и этого мне хватает


Реализацию можно посмотреть тут.


Предвещая вопрос "А почему же не рандом?"


Да, есть такой легендарный код


function uuidv4() {    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);        return v.toString(16);    });}

В моем случае на бэкенде UUID используется как первичный ключ.


Когда первые байты ключа идут по порядку больше вероятность, что новая запись встанет в конец таблицы. Даже если на клиенте будет запущена синхронизация. Ведь вряд ли юзер выполнит синхронизацию данных внесенных полгода назад и СУБД будет сдвигать половину таблицы.


В случае же с рандомом данные будут вставляться в табличку куда ни попадя.

Источник: habr.com
К списку статей
Опубликовано: 20.02.2021 18:04:03
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Javascript

Браузеры

Frontend

Типы данных

Uuid

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru