Лучшие практики SPA для аутентификации и управления сеансами

При создании приложений стиля SPA с использованием таких рамок, как Angular, Ember, React и т. Д., Что люди считают лучшими методами аутентификации и управления сеансами? Я могу придумать пару способов рассмотрения проблемы.

  1. Относитесь к нему не иначе, как к аутентификации с помощью обычного веб-приложения, предполагая, что API и UI имеют один и тот же исходный домен.

    Вероятно, это связано с наличием сессионного файла cookie, хранилища сеансов на стороне сервера и, возможно, некоторой конечной точки сеанса API, с которой может пройти аутентифицированный веб-интерфейс, чтобы получить текущую пользовательскую информацию, чтобы помочь в персонализации или, возможно, даже определить роли / возможности на стороне клиента. Сервер по-прежнему будет применять правила защиты доступа к данным, конечно, пользовательский интерфейс будет использовать эту информацию только для настройки опыта.

  2. Относитесь к нему, как к любому стороннему клиенту, используя общеansible API и аутентифицируясь с помощью какой-либо системы токенов, аналогичной OAuth. Этот токен-механизм будет использоваться клиентским интерфейсом для аутентификации каждого запроса, поданного на API-интерфейс сервера.

Я не очень разбираюсь в этом, но № 1, кажется, вполне достаточен для подавляющего большинства случаев, но мне бы хотелось услышать более опытные мнения.

    Этот вопрос был рассмотрен в несколько иной форме, подробно:

    Аутентификация RESTful

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

    Javascript Crypto – беззастенчивый

    Статья Матасано об этом известна, но уроки, содержащиеся в ней, очень важны:

    http://www.matasano.com/articles/javascript-cryptography/

    Обобщить:

    • Атака «человек-в-середине» может тривиально заменить ваш
    • Атака «человек в середине» тривиально против страницы, которая обслуживает любой ресурс по не-SSL-соединению.
    • Как только у вас есть SSL, вы все равно используете реальный крипто.

    И добавить свое собственное следствие:

    • Успешная атака XSS может привести к тому, что злоумышленник выполнит код в браузере вашего клиента, даже если вы используете SSL – так что, даже если у вас есть каждый люк, то ваш криптографический код браузера все равно может выйти из строя, если ваш злоумышленник найдет способ выполнить любой код javascript в чужом браузере.

    Это делает невозможным или глупым многие схемы аутентификации RESTful, если вы собираетесь использовать клиент JavaScript. Давайте посмотрим!

    HTTP Basic Auth

    Прежде всего, HTTP Basic Auth. Простейшая схема: просто передайте имя и пароль с каждым запросом.

    Это, конечно, абсолютно требует SSL, потому что вы передаете Base64 (обратимо) кодированное имя и пароль с каждым запросом. Любой, кто прослушивает эту строку, может извлекать имя пользователя и пароль тривиально. Большинство аргументов «Basic Auth is insecure» исходят из места «Basic Auth over HTTP», что является ужасной идеей.

    В браузере предусмотрена поддержка HTTP Basic Auth, но она уродлива, как грех, и вы, вероятно, не должны использовать ее для своего приложения. Альтернативой, однако, является спрятать имя пользователя и пароль в JavaScript.

    Это самое RESTful решение. Сервер не требует каких-либо знаний о состоянии и аутентифицирует каждое индивидуальное взаимодействие с пользователем. Некоторые энтузиасты REST (в основном, соломенные) настаивают на том, что поддержание любого состояния является ересью и будет пениться во рту, если вы думаете о каком-либо другом методе проверки подлинности. Существуют теоретические преимущества для такого соответствия стандартам – он поддерживается Apache из коробки – вы можете хранить ваши объекты в виде файлов в папках, защищенных файлами .htaccess, если вам угодно!

    Проблема ? Вы используете на стороне клиента имя пользователя и пароль. Это дает evil.ru лучший треск на нем – даже самые простые из уязвимостей XSS могут привести к тому, что клиент будет бить свое имя пользователя и пароль злому серверу. Вы можете попытаться смягчить этот риск, хешируя и засовывая пароль, но помните: JavaScript Crypto является беззаботным . Вы могли бы смягчить этот риск, оставив его до базовой поддержки браузера, но … уродливым, как грех, как упоминалось ранее.

    HTTP Digest Auth

    Возможно ли аутентификация дайджеста с помощью jQuery?

    Более «безопасный» auth, это запрос хеша запроса / ответа. За исключением JavaScript Crypto является Hopeless , поэтому он работает только через SSL, и вы все равно должны кэшировать имя пользователя и пароль на стороне клиента, что делает его более сложным, чем HTTP Basic Auth, но не более безопасным .

    Аутентификация запроса с дополнительными параметрами подписи.

    Еще один «безопасный» auth, где вы шифруете свои параметры с помощью данных nonce и time (для защиты от повторных и временных атак) и отправки. Одним из лучших примеров этого является протокол OAuth 1.0, который, насколько мне известно, является довольно сложным способом реализации проверки подлинности на сервере REST.

    http://tools.ietf.org/html/rfc5849

    О, но нет клиентов OAuth 1.0 для JavaScript. Зачем?

    Помните, что JavaScript Crypto является Безнадежным . JavaScript не может участвовать в OAuth 1.0 без SSL, и вам все равно нужно локально хранить имя пользователя и пароль клиента, что ставит его в ту же категорию, что и Digest Auth, – это сложнее, чем HTTP Basic Auth, но он не более безопасен .

    знак

    Пользователь отправляет имя пользователя и пароль, а взамен получает токен, который может использоваться для аутентификации запросов.

    Это немного более безопасно, чем HTTP Basic Auth, поскольку, как только транзакция имени пользователя / пароля будет завершена, вы можете отбросить конфиденциальные данные. Это также меньше RESTful, поскольку токены составляют «состояние» и усложняют реализацию сервера.

    SSL еще

    Тем не менее, вы все равно должны отправить это начальное имя пользователя и пароль, чтобы получить токен. Чувствительная информация по-прежнему касается вашего компрометирующего JavaScript.

    Чтобы защитить учетные данные пользователя, вам все равно нужно избегать атаки злоумышленников из вашего JavaScript, и вам все равно необходимо отправить имя пользователя и пароль по кабелю. Требуется SSL.

    Срок действия токена

    Обычно применяются политики маркеров, такие как «эй, когда этот токен слишком длинный, отбросьте его и повторите проверку подлинности пользователя». или «Я уверен, что единственным IP-адресом, разрешенным для использования этого токена, является XXX.XXX.XXX.XXX ». Многие из этих политик являются довольно хорошими идеями.

    Firesheeping

    Однако использование токена без SSL по-прежнему уязвим для атаки под названием «sidejacking»: http://codebutler.github.io/firesheep/

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

    tl; dr: Отправка незашифрованных токенов по проводу означает, что злоумышленники могут легко набить эти жетоны и притворяться вашим пользователем. FireSheep – это программа, которая делает это очень просто.

    Отдельная, более безопасная зона

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

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

    Cookie (просто означает токен)

    Возможно (и распространено) поставить токен аутентификации в файл cookie. Это не изменяет никаких свойств auth с помощью токена, это более удобная вещь. Все предыдущие аргументы все еще применяются.

    Сессия (еще только означает токен)

    Session Auth – это только аутентификация Token, но с несколькими отличиями, которые делают это несколько иначе:

    • Пользователи начинают с неавторизованного токена.
    • Бэкэнд поддерживает объект состояния, привязанный к токену пользователя.
    • Токен предоставляется в файле cookie.
    • Среда приложения абстрагирует детали от вас.

    Помимо этого, однако, это ничем не отличается от Token Auth.

    Это еще больше удаляется от реализации RESTful – с объектами состояния, которые вы продвигаете дальше и дальше по пути простого RPC на сервере с сохранением состояния.

    OAuth 2.0

    В OAuth 2.0 рассматривается проблема «Как программное обеспечение A предоставляет ПО B доступ к данным пользователя X без программного обеспечения B, имеющего доступ к учетным данным пользователя X».

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

    По сути, OAuth 2.0 – это всего лишь протокол токена. Он обладает теми же свойствами, что и другие протоколы токенов – для защиты этих токенов вам все еще нужен SSL, он просто изменяет способ генерации этих токенов.

    OAuth 2.0 может помочь вам двумя способами:

    • Предоставление аутентификации / информации другим пользователям
    • Получение аутентификации / информации от других пользователей

    Но когда дело доходит до этого, вы просто … используете жетоны.

    Вернуться к вашему вопросу

    Таким образом, вопрос, который вы задаете, – «должен ли я хранить токен в файле cookie и настроить автоматическое управление сеансом моей среды на детали, или я должен хранить свой токен в Javascript и сам обрабатывать эти данные?»

    И ответ: делайте то, что делает вас счастливыми .

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

    Мне 21, поэтому SSL да

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

    Вы можете повысить безопасность в процессе аутентификации с помощью JWT (JSON Web Tokens) и SSL / HTTPS.

    Идентификатор Basic Auth / Session можно украсть через:

    • Атака MITM (Man-In-The-Middle) – без SSL / HTTPS
    • Злоумышленник получает доступ к компьютеру пользователя
    • XSS

    Используя JWT, вы шифруете данные аутентификации пользователя и сохраняете их на клиенте и отправляете вместе с каждым запросом API, где сервер / API проверяет токен. Он не может быть расшифрован / прочитан без закрытого ключа (который хранится в сервере / API). Прочитайте обновление .

    Новый (более безопасный) stream будет:

    Авторизоваться

    • Пользователь регистрируется и отправляет учетные данные для входа в API (через SSL / HTTPS)
    • API получает учетные данные
    • Если это действительно:
      • Зарегистрировать новый сеанс в базе данных
      • Шифровать идентификатор пользователя, идентификатор сеанса, IP-адрес, временную метку и т. Д. В JWT с закрытым ключом.
    • API отправляет маркер JWT обратно клиенту (через SSL / HTTPS)
    • Клиент получает токен JWT и хранит в localStorage / cookie

    Каждый запрос API

    • Пользователь отправляет HTTP-запрос в API (через SSL / HTTPS) с сохраненным токеном JWT в HTTP-заголовке
    • API читает HTTP-заголовок и расшифровывает токен JWT с его закрытым ключом
    • API проверяет токен JWT, соответствует IP-адресу из HTTP-запроса с таковым в токере JWT и проверяет, закончился ли сеанс
    • Если это действительно:
      • Обратный ответ с запрошенным контентом
    • Если это недействительно:
      • Выбросить исключение (403/401)
      • Инфляция флага в системе
      • Отправьте электронное письмо пользователю.

    Обновлено 30.07.15:

    Полезная нагрузка / претензии JWT действительно может быть прочитана без секретного ключа (секретная), и ее небезопасно хранить в localStorage. Прошу прощения за эти ложные заявления. Однако они, похоже, работают над стандартом JWE (JSON Web Encryption) .

    Я реализовал это, сохранив заявки (userID, exp) в JWT, подписал его с закрытым ключом (секретным), который API / Бэкэнд знает и хранит в качестве защищенного файла cookie HttpOnly на клиенте. Таким образом, он не может быть прочитан с помощью XSS и не может быть обработан, иначе JWT не сможет проверить подпись. Кроме того, используя безопасный файл cookie HttpOnly , вы убедитесь, что cookie отправляется только через HTTP-запросы (недоступные для скрипта) и отправляется только через безопасное соединение (HTTPS).

    Обновлено 17.07.16:

    JWT по своей природе являются лицами без гражданства. Это означает, что они недействительны / истекают. Добавляя SessionID в утверждениях токена, вы делаете его с сохранением состояния, поскольку его действительность теперь не зависит только от проверки подписи и даты истечения срока действия, это также зависит от состояния сеанса на сервере. Однако потенциал роста – это то, что вы можете легко лишить токенов / сеансов, чего вы не могли бы сделать с помощью JVT без гражданства.

    Я бы пошел на вторую, символическую систему.

    Вы знали о ember-auth или ember-simple-auth ? Они оба используют систему на основе токенов, например, ember-simple-auth:

    Легкая и ненавязчивая библиотека для реализации аутентификации на токенах в приложениях Ember.js. http://ember-simple-auth.simplabs.com

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

    Существует также пример версии Ember App Kit для ember-simple-auth: рабочий пример набора ember-app-kit с использованием ember-simple-auth для проверки подлинности OAuth2.

    Давайте будем гением компьютера.