Как стать автором
Обновить

Комментарии 23

Не стоит: Передавать ID Token, Access Token, Refresh Token из серверной части агенту пользователя (браузер)

Можете пожалуйста обьяснить почему? В браузере ведь должен быть какой-то секрет чтобы делать повторные обращения к сервису без повторного логина. Чем авторизационная кука / айди сессии лучше токенов? они ведь дают одинаковый уровень доступа

Насколько я понимаю, так как есть бэк, то вся обработка там, а фронт это только картинки, ну и соответсвенно между беком и фронтом можно просто воспользоваться обычными сессиями. Поэтому передача на фронт креденшионалов лишена смысла.

Если на беке микросервисы, то не лишена — JWT позволяет обойтись без центрального хранилища сессий и проверять access токены просто валидируя подпись (конечно, если вам не нужен механизм отзыва access токенов, или его можно игнорировать для большинства вызовов проверяя отзыв только перед действительно страшными операциями из серии «удалить все, я уверен»).


Кроме того, это позволяет перенести проверку токенов в API Gateway как указано в статье, и вообще вынести аутентификацию в отдельный Identity Provider сервис (есть стандартные реализации IdP). Выделение IdP, в свою очередь, позволяет легко и непринуждённо добавлять всякие 3-party SSO, двухфакторные аутентификации и т.п. (для других сервисов ничего не меняется) + IdP отвечает за refresh токены, их обработку и отзыв.


Ну и… ведь в “JS Only App” токены как я понимаю как раз в браузере и храниться (хотя явно этого я в статье не увидел, но вроде подразумевается) — непонятно почему в одном месте это плюс, а в другом минус.


Напоследок, мне показалось есть путаница с PKCE — насколько я понимаю оно к хранению/токенам никакого отношения не имеет, это просто более безопасный способ получить токен, который закрывает некоторые потенциальные атаки на стадии логина построенные вокруг перехвата authorization code. Сами токены при этом все те же.

Там скорее всего имеется ввиду что бэк только для фронта и логики там практически нет. А вот дальше где-то еще и микросервисы и все остальное.
Доброе утро!
Спасибо за ваш вопрос. Здесь важно обратить внимание на то, что эта рекомендация дается для приложения "JavaScript application with a backend".
Сейчас токены чаще всего как случайный набор символов не используются. Многие решения формируют токены в формате JWT. И в токенах может содержаться значимая информация (встречаются реализации с ФИО, телефонами, email и т.д.).
Поэтому для JavaScript application with a backend стоит использовать:
  • классический Authorization Code Grant, когда ClientId и Secret хранятся только в бэке и обмен идет в защищенной сети (можно без PKCE тогда и использовать конфиденциального клиента), обмен токенами идет только в бэке,
  • либо мы не обращаем внимание на то, что у нас присутствует бэкенд, и реализауем сценарий как для JavaScript application with no backend, но по всем правилам для публичных клиентов: Authorization Code Grant Flow with PKCE с публичным клиентом (у публичного клиента нет секрета, а PKCE вводится для защиты только процесса аутентификации пользователя в таком случае) и с добавлением API Gateway, так как для этого сценария строже требуется выполнять проверки токена (redirect uri, cors, clientId, подпись и т.д.) и исключать передачу персональных данных в токене.


Для классического Authorization Code Grant схему дополнила информацией по тому, в какой момент еще формируются пользовательская и клиентская сессия:


(надеюсь, читаемо)

Лучше refresh token положить в куку, а куку зашифровать. Тогда JS не сможет залезть куда не нужно, а сервер сможет обновить сессию на ресурсном сервере когда потребуется.

Добрый день. да, верно, добавлю в таблицу.
Зря наверное они избавляются от resourse owner credentionals grant так как это нормальная авторизация для клиентов, где нет браузера.
И почему тогда оставляют client credentionals — там тоже пароль в открытом виде доступен.
ЗЫ В таблицах я бы все-таки не смешивал доступ клиента и овнера — это разного уровня доступы.

И ещё хотелось бы увидеть какой-то стандартный способ логинится не передавая пароль на сервер (типа как HTTPS handshake который генерирует ключ для соединения не передавая его по сети). Не то что бы я не доверял HTTPS, но его часто терминируют на лоад балансерах, да и залогировать его можно неудачно.

так есть уже стандарт — webauthn — без паролей.

Эм нет, вы меня не поняли. С паролями, но без передачи пароля по сети. Условно говоря (фантазируя, но так, чтоб передать идею)


  • при регистрации пользователя (единоразово):
    1) попросить придумать пароль, оставить пароль в браузере (на сервер не слать)
    2) сгенерировать случайную соль, положить ее в базу и передать в браузер
    3) в браузере, на основе пароля и соли — детерминированно сгенерировать пару публичный + приватный ключ
    4) публичный ключ отправить на сервер и положить в базу


  • при логине
    1) отправить в браузер соль и некое случайное число (большое)
    2) в браузере — сгенерировать приватный и публичный ключ так же как при регистрации (пользователь должен ввести пароль, но пароль не уходит в сеть)
    3) подписать приватным колючем случайное число из шага (1) и отправить на сервер
    4) сервер проверяет подпись ранее публичным ключем из базы, подпись дрожа быть корректной а случайное число соответствовать (1)



Таким образом, мы все ещё используем пароль, но он никогда не передаётся по сети ни в каком виде. Генерировать ключи чём-то вроде PBKDF2/Argon2, но ассиметричным (как вариант — пароль + соль => криптографический хеш => использовать как seed для криптографического генератора случайных чисел => ГСЧ использовать для генерации обычного RSA ключа)


Но это все на уровне кухонных разговоров и не точно: я не настоящий сварщик, а с криптографией шутки плохи

Спасибо, это ключевое слово я и искал

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

Как я понял, в таком варианте пытаются защитится не от перебора пароля, а от перехвата пароля отправляемого клиентом через сеть (и даже от того, что бы сервер в принципе мог узнать этот пароль, мало-ли куда он может его слить).
PS: от перебора можно по другому защищаться (rate-limit, captcha и др.)

Да.


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

Здравствуйте!
Спасибо за вопрос.
client credentionals — его основное предназначение — это обмен между приложениями (бэк ту бэк) Например, стороннее приложение использует ваш сервис, который вы не хотите делать публичным, а предоставляете только авторизованным системам.

Я этот момент тоже не совсем понимаю.
Как строить "правильно" с ОAuth2.1 нативной аппы которой доверяешь в имплементации (сам выпускаешь)?
Или этот стандарт просто решил не предлагать ничего для этого кейса?

Если я вас правильно поняла, то вот тут предлагается описание для данного сценария. Т.е. использовать публичного клиента (без секрета) + соответственно, PKCE обязательно, как следует из требований к потоку Authorization Code Grant выше.

Если я правильно понимаю Authorization Code Grant, то нужно что-бы мое скажем приложение открывало browser в котором логин/пароль задаются, тем самым не проходя через само приложение…
Это все очень условно секьюрно в случае с public app. И да можно наверно сойтись на том, что browser мы доверяем как-то больше чем аппликушечке от дяди Васи.


НО! мой сценарий не тот. Я сам строю свою аппликушечку. У меня нет никакой причины доверять browser больше чем аппе написаной моей крутой коммандой, для нашей же API наших же в конце концов юзеров (но просто другой API предоставленной)
Зачем мне открывать browser в моей аппе? Я считаю это ужасным UX к примеру… и я не один такой, я вижу кучу аппов не делающих это. Они просто все плевали на OAuth?
Вот этот момент мне не понятен.


P.S.
Ещё два года назад все было Ок:
https://developer.okta.com/blog/2018/06/29/what-is-the-oauth2-password-grant
что поменялось и как это теперь реализовывать?

Authorization Code Grant в 2.1 не требует обязательного использования какого-то готового агента в виде браузера. В принципе, есть даже драфт, который как бы специально для браузерных приложений как дополнение создан к OAuth, т.е. в самом OAuth нет однозначного требования, что ваше приложение должно базироваться только на браузерных агентах. Вы можете и свое разработать. Главное, что меняется в 2.1 — это то, что нам говорят, что теперь основными сценариями при разработке потоков аутентификации мы должны пользоваться только Authorization Code Grant с PKCE, Client Credentials Grant и еще для дивайсов, думаю, вот этот RFC8628 войдет.

я вижу кучу аппов не делающих это. Они просто все плевали на OAuth?
— вероятно, это риторический вопрос. Если спрашиваете у меня, то в моей практике имеются случаи, когда заказчик «плюет» на безопасность или соответствие каким-либо спецификациям разрабатываемого приложения.

что поменялось и как это теперь реализовывать?

Я надеюсь, что OAuth2.1 и последующие будет понятнее для потребителей, и допускать меньше вольностей в интерпретации. Сейчас, чтобы разобраться, как работать по OAuth, нужно еще рад RFC и драфтов изучить, которые выпускались к фреимворку, как дополнение.
Что поменялось я писала выше, но продублирую еще раз здесь:
(1) Потоки Implicit grant (response_type=token) и Resource Owner Password Credentials исключаются из документа.
(2) Аuthorization code grant расширили кодом PKCE (RFC7636) как для публично, так и конфиденциального клиентов.
(3) Redirect URIs должны будут всегда явно задаваться на сервере авторизации.
(4) Refresh токены для публичных клиентов должны ограничиваться, либо использоваться не более 1 раза.

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

Ой, если и есть эмоциональность, то только ради заострения вопроса, ничего-больше в это не вкладываю. Вам огромное спасибо за попытку разобраться!!!
Давайте попробуем:


Authorization Code Grant в 2.1 не требует обязательного использования какого-то готового агента в виде браузера

Наверно вы правы формально "user agent" не обязательно browser.
Но "user agent" это то, кому пользователь больше доверяет. "Агент пользователя", установленный (им) на его устройстве — главное что не вами!..
И именно в этом фишка в федеративном сценарии и всем этом Authorization Code Grant. Пароли не проходят никак через вашу апп!


Resource Owner Password Credentials исключаются из документа.

так вот в этом и вопрос и что в замен?


Моя личная догадка в том, что просто OAuth перестает описывать "не федеративный" сценарий коим является тот сценарий который я описываю:
Мои пользователи и их credentials проходят везде мой код и в App и в Backend…
И поэтому, воизбежания OAuth 2.1 просто перестает это описывать в своем стандарте, обьявляя мой случай проприетарным.


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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории