LINUX.ORG.RU

Использование UUIDv7 в качестве токена авторизации

 ,


1

1

UUID v4 не рекомендуется использовать в качестве токенов авторизации: https://security.stackexchange.com/questions/157270/using-v4-uuid-for-authent...

Do not assume that UUIDs are hard to guess; they should not be used as security capabilities (identifiers whose mere possession grants access), for example. A predictable random number source will exacerbate the situation.

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

Но тем не менее я даже UUID v4 не хочу использовать, не то что криптостойкий рандом в качестве токена авторизации - я буду хранить токены в Postgres, а Postgres, поговаривают, плохо работает с UNIQUE колонками со случайными данными - B-дерево распухает.

Хочу использовать в качестве токенов авторизации UUID v7 - они должны быть по заверению авторов дружелюбны к индексам баз данных. Но беда в том, что их ещё проще угадать, ибо там половина бит даже не рандом неизвестного качества, а вообще метка времени.

Но что если в БД хранить UUID, а юзеру отдавать и от юзера принимать JWT, где UUID хранить в JTI (ну и срок жизни токена, если надо, в exp зашить, stateless фичами JWT мы пользоваться всё равно не будем, нам от него по сути только цифровая подпись токена нужна).

Теперь злоумышленнику мало угадать UUID, ему ещё надо его подписать секретом приложения, который он не знает (в качестве небольшого бонуса - если утечёт дамп БД - без конфига приложения он всё равно не позволит угнать сессии). И наоборот, если утёк секрет JWT, чтобы увести сессию надо ещё угадать UUID (что не невозможно, но всё равно требует усилий). С другой стороны, приложение выборку из БД делает по jti, который UUID v7, который хорошо дружит с индексами БД.

Что думаете о такой схеме?

★★★★★

Postgres, поговаривают, плохо работает с UNIQUE колонками со случайными данными

какая интереснейшая история. Половина книжки по структурам данных посвящена вопросу: как положить в структуру данных поток, имеющий неприятные паттерны, т.е. неслучайный.

Как раз случайные то идеально ложатся в б-дерево.

Используй рандом, кодируй его в base64 или base85 и проблем не знай.

Складывать в базу данных или таскать JWT - это тебе на выбор.

max_lapshin ★★★★★
()

Ужас, ну что за бред? Какой идиот придумал делать стандарты на случайные числа (uuid), да ещё и разных версий? Просто используй getrandom() нужной длины. Да, длину совершенно не обязательно привязывать к чьей-то стандартописательской графомании.

JWT

Я уже не помню подробностей, но это творение коллективного разума веб-макак и не рекомендую на него смотреть.

я буду хранить токены в Postgres, а Postgres, поговаривают, плохо работает с UNIQUE колонками со случайными данными - B-дерево распухает.

Думаю об этом стоит думать когда столнёшься с реальной проблемой, а не теоретической. И зачем тебе b-дерево для рандом чисел? postgres не умеет хеш-таблицы использовать?

firkax ★★★★★
()

поговаривают, плохо работает с UNIQUE колонками со случайными данными - B-дерево распухает

Поговаривают по деревням, а у нас точная наука. Думал почему оно может распухать?

  • Потому что GOVNUID длинный. Ещё, небось, и в виде строки будешь его хранить, потому что нативных типов для 100500 версий этого уродства в постгресе наверняка нет.
  • Потому что GOVNUID нелокальный (какие-то версии, видимо, которые начинаются с рандома, а не времени). Поэтому новые записи пишутся с равной вероятностью по всему индексу, а не в одну активную страницу, и все эти страницы нужно постоянно дёргать с/на диск, кэшировать в памяти и нет возможности как следует отвакумировать.

Что думаете о такой схеме?

Откуда вообще в твою голову пришла идея взять GOVNUID? Нужны случайные данные - положи их в целое нужного размера. Нужно особое распределение для локальности - сделай какое нужно распределение, записав в старшие несколько бит текущее время.

anonymous
()
Ответ на: комментарий от firkax

Хе-хе - у дуракоФФ мысли … тогось :) … :

select
  -- timestamp
  lpad(to_hex(((extract(epoch from now()) * 1000)::bigint >> 16)), 8, '0') || '-' ||
  lpad(to_hex(((extract(epoch from now()) * 1000
    + (date_part('milliseconds', now())::bigint % 1000))::bigint & 0xffff)), 4, '0') || '-' ||
  -- version / rand_a
  lpad(to_hex((0x7000 + (random() * 0x0fff)::int)), 4, '0') || '-' ||
  -- variant / rand_b
  lpad(to_hex((0x8000 + (random() * 0x3fff)::int)), 4, '0') || '-' ||
  -- rand_b
  lpad(to_hex((floor(random() * (2^48))::bigint >> 16)), 12, '0') AS value;

И случайного там ~~половина, а в начале так вообще timestamp … :)

anonymous
()

У нас есть выбор между:

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

Выбор очевиден!

Что значит, ты не будешь пользоваться stateless фичами JWT? Ты не будешь проверять его подпись что ли? Тогда зачем он нужен? Можешь положить свой UUID в обычный JSON тогда, для красоты.

Смысла скрещивать UUID (как первичный ключ авторизации) c JWT нет. JWT подтвердит тебе, что токен (сам JWT) был выпущен твоим сервером, поэтому внутрь можешь положить все что угодно, хоть 1, 2, 3 — клиенты не смогут его подделать.

Этот топик должен служить напоминанием доверить аутентификацию профессионалам.

anonymous
()

токен - это рандомный набор символов. uuid же нужен, например, в базах данных как primary key. то что ты делаешь наркомания. токены эти не должны храниться где-то кроме пользовательского устройства. в JWT прошиваешь время обновления пароля. если пользователя ломают, то он просто меняет пароль, и токен больше не валиден (время изменения пароля в базе именилось)

rtxtxtrx ★★★
()
Последнее исправление: rtxtxtrx (всего исправлений: 1)
Ответ на: комментарий от anonymous

программисты на самом деле глупые люди. они напыщенные как правило и думают, что умнее гуманитариев, если у них есть вышка в парашном мфти, который закалабился с инфоцыганами, продающими курсы… не хотят они думать. и все эти stateless им ничего не говорят. они думают, что rest - это про использование 4 http-методов, а не горизонтальное масштабирование

rtxtxtrx ★★★
()