Комментарии 39
Понимаю, что даром бы вот это все не городили, но все же? Централизированная аутентификация для разных продуктов, большая секурность (на основе чего?)?
Я бы не сказал, что токены "лучше" или "хуже", у них есть свои области применимости, как и у кук. Например, HTTP-only Secure куки признаны одним из лучших механизмов хранения сессии. IdentityServer4 хранит сессию пользователя именно в куке по умолчанию.
Для того, чтобы толково ответить на Ваш вопрос понадобится написать немаленькую такую статью, не думаю, что это хорошая идея, тем более, что многие это уже сделали.
Вот тут, если пролистаете до реального описания кук и токенов, может быть интересно почитать, например.
Если совсем коротко, то мне на ум приходят такие варианты.
- Требуется выдавать "токены" одним центром авторизации для многих ресурсов. Возможно, это даже не ваш центр авторизации (Google, Facebook, Auth0 и т.д.).
- Требуется логика, которая сильно выигрывает от stateless-механизма. Как тут в примере про отель.
- Проблемой для реализуемого сценария является сам протокол кук, и связанная с ним специфика вроде отправки кук при каждом GET-запросе по умолчанию вообще, и CSRF-уязвимости в частности.
А как насчет такой вот статьи Stop using JWT for sessions и ее продолжения?
Ну во-первых, ни моя статья, ни мои комментарии не содержат предложений использовать JWT для сессий.
Во вторых, статью я читал, она ИМХО построена по старому-доброму принципу "вначале хорошенько передёрнуть, потом всё эмоционально развенчивать". Нормальное обсуждение статьи тут. Если любите такой жанр, можете почитать ещё эту.
Правильно говорить не "старые добрые сессии оказываются не хуже", а "старые добрые куки оказываются не хуже для реализации сессий".
Если задача заключается не в реализации сессий, а в защите доступа к API — то токены справляются даже лучше кук, потому что их не надо дополнительно защищать от CSRF-атаки.
А еще, основная фишка токенов – stateless аутентификация. Но она получается не на столько секьюрной как stateful с помощью сессий.
Куки тоже от сторонних скриптов не спасают. Да, нельзя украсть http only куку — но никто не мешает прямо со страницы делать запросы. Иными словами, успешный XSS проламывает любую защиту.
Если же хочется защититься именно от кражи для повышения порога атаки — токен можно привязать к Origin.
Да, про stateless аутентификацию. Она делается не с любыми токенами, а только с подписанными (например, с JWT). Но не надо думать, что только токены можно подписывать — с куками такое тоже можно провернуть. И недостатки у них будут общие — отсутствие возможности логаута.
Тут внезапно не всё так очевидно. Вообще говоря, приложения, которые получают доступ к ресурсу на основе Bearer-токенов обычно защищённее, т.к. атакующий не может полагаться на стандарт раз, и access_token'ы обычно делают живущими недолго два. Однако, если у вас SPA с восстановлением текущего состояния из URL, при атаке через CSRF может так случится, что приложение прекрасно восстановит контекст из URL и localStorage, а затем сделает нужный хакеру запрос.
Так что такие приложения, вообще говоря, труднее атаковать — да, но защищать именно от CSRF-атак их тоже нужно.
Это вы уже описали атаку на приложение, а не на API. Соответственно, и защищать от такой атаки нужно само приложение.
CSRF тут, кстати, все равно не нужен. Надо лишь продолжать соблюдать нечто вроде принципа разделения GET и POST — переход по внутреннему роуту не должен вызывать никаких запросов на изменение, все запросы на изменение должны генерироваться только событиями. И не забыть запретить запуск во фрейме.
Это вы уже описали атаку на приложение, а не на API. Соответственно, и защищать от такой атаки нужно само приложение.
Есть такое.
По остальному согласен. Ну и anti-CSRF-токены различные.
А вот anti-CSRF-токены как раз тут и не помогут. Потому что чтобы такой токен работал — его надо будет запихнуть в строку адреса, но это убьет саму идею адресации: такой защищенный токеном адрес нельзя будет ни другу передать, ни в закладки добавить. Проще сразу делать SPA без роутинга и игр с URL.
Вот именно, делать shareable полузаполненную форму смысла большого нет — а значит, и вызвать ее через URL атакующий не сможет.
Я уже писал, от XSS не спасает ничего.
Повторяю: антиCSRF-токен не защищает от Self-XSS атаки.
«Self-XSS» — это, строго говоря, не совсем XSS, это гораздо больше и вообще о другом. Это выполнение произвольного кода в консоли. Этот код может, например, выполнять GET, а затем POST-запрос. С точки зрения вектора атаки на приложение — это будет CSRF. Да, можно было бы попытаться провести XSS самого сайта (но сложнее т.к. проще поместить «рекомендации» по действиям с консолью на другой сайт). Ваш сайт даже может выводить предупреждение в консоль, как Фейсбук, ему это не поможет.
TL;DR; Мой пример не про XSS.
Меня смутило «Я уже писал, от XSS не спасает ничего.» по поводу CSRF-примера.
Тут есть общий момент с XSS — выполнение произвольного кода в контексте страницы. Этого достаточно для того чтобы обойти анти-CSRF проверку, потому что у злонамеренного кода есть полный доступ к состоянию вашего приложения, в том числе к любым секретным токенам.
Токен генерируется сервером? Отлично, попросим сервер сгенерировать нам токен.
Токен записан в LocalStorage? Отлично, прочитаем его оттуда.
Токен записан в локальную переменную в замыкании? Отлично, переопределим fetch
или JSON.stringify
и дождемся когда приложение само отдаст нам токен.
Только вот когда это читаешь, оторопь берет – неужели вот это ВСЁ нужно только для обеспечения аутентификации / авторизации. Бедные новички!
Да, судя по документации, если взять IdentityServer4, то не понадобится больше вообще ничего. Тут тебе и SSO, и разные типы клиентов, и аутентификация между разными микросервисами.
Но для простых приложений, бывает быстрее накидать свою application-specific схему авторизации. Просто на основе базовых знаний протокола HTTP и известных уязвимостей. Чем разбираться со всеми этими claims, issuers, audiences, access-refresh tokens etc.
Возможно, но я лично придерживаюсь в этом вопросе принципа "never roll your own".
Это на самом деле абсолютно верный принцип. Но тут у меня претензии не к самим протоколам и существующим реализациям, а к их документации.
Все туториалы вываливают сразу на человека кучу инфы. Я еще не видел, чтобы гайд по аутентификации был построен так:
- Вам нужна простая авторизация – вот минимальный набор действий.
- У Вас несколько приложений – настройте еще это и это.
- Нужно SSO – добавьте вот такую опцию.
Почему, например, имея ровно один сервер, и ровно один браузерный клиент, я должен указывать какие-то Issuer и Audience? И еще куча неочевидных моментов.
И за всем этим очень трудно уследить. Для каждого протокола авторизации есть несколько версий. Для каждой версии – несколько реалкизаций со своими версиями. У каждой версии реализации новый формат конфигурации.
Почему, например, имея ровно один сервер, и ровно один браузерный клиент, я должен указывать какие-то Issuer и Audience? И еще куча неочевидных моментов.
А зачем вам SSO с одним сервером и одним браузерным клиентом? Для таких случаев существует ASP.NET Identity
Или даже что-то свое на формах слепить можно
И есть еще один момент. Когда я настраиваю авторизацию по туториалу, меня не покидает ощущение – "а все ли я сделал правильно"? Я выполнил какие-то действия без понимания, как каждое из них влияет на безопасность приложения. Защищает ли описанная в туториале конфигурация именно от тех видов атак, от которых я планирую защитить приложение?
Или после каждой настройки аутентификации нужно проводить пентест? Так мы никогда не сможем начать наконец работу над бизнес-логикой проекта. Ведь авторизация настраивается как правило вначале.
- В принципе, ощущение игрушечности существующих туториалов и было одной из мотиваций того, что я написал yet another. По моей задумке, он должен быть в этом смысле лучше.
- Вы в любом случае будете делать пентесты, скорее всего ещё и будете использовать автоматические.
В любом туториале (не обязательно по безопасности) рассказывается КАК сделать что-то.
А вот ЗАЧЕМ делать что-то не рассказывается, потому что без этого приложение как правило не будет работать вообще. Но вот с уязвимостями как раз нет очевидных вещей.
Например, если не прописать connection string – то мы не сможем подключиться к БД.
А если не проставить в авторизационный токен expiration time, то приложение будет работать? Да. Но появится уязвимость.
Имплементация OpenId Connect в ASP.NET Core при помощи IdentityServer4 и oidc-client