СПА-рекомендации по аутентификации и управления сеансами


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

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

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

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

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

3 229

3 ответа:

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

RESTful Authentication

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

Javascript Crypto безнадежен

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

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

подведем итоги:

  • атака человека в середине может тривиально заменить ваш крипто-код на <script> function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script>
  • атака "человек в середине" тривиальна против страницы, которая обслуживает любой ресурс через соединение без SSL.
  • как только у вас есть SSL, вы используете реальный крипто в любом случае.

и добавить следствие моего собственные:

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

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

HTTP Basic Auth

в первую очередь, HTTP Basic Auth. Самая простая из схем: просто передайте имя и пароль с каждым запросом.

Это, конечно, абсолютно требует SSL, потому что вы передаете Base64 (обратимо) закодированное имя и пароль с каждым запросом. Любой слушающий на линии может извлечь имя пользователя и пароль тривиально. Большинство "базовой аутентификации является небезопасным" аргументы от "basic авторизации через HTTP", которая является ужасная идея.

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

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

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

http Digest Auth

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

более "безопасный" auth, это a запрос / ответ хэш-вызов. Кроме JavaScript Crypto безнадежен, поэтому он работает только через SSL, и вам все равно нужно кэшировать имя пользователя и пароль на стороне клиента, что делает его более сложным, чем HTTP Basic Auth, но больше не безопасно.

проверка подлинности запроса с дополнительными параметрами подписи.

еще один более "безопасный" auth, где вы шифруете свои параметры с помощью данных nonce и синхронизации (для защиты от повторения и синхронизации атаки) и отправить. Одним из лучших примеров этого является протокол 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, потому что как только транзакция имени пользователя / пароля будет завершена, вы можете отказаться от конфиденциальные данные. Это также менее спокойно, так как токены составляют "состояние" и усложняют реализацию сервера.

SSL все еще

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

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

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

обычно применяются политики токенов, такие как " Эй, когда этот токен слишком долго существует, отбросьте его и снова выполните аутентификацию пользователя."или "я уверен, что единственным IP-адресом, разрешенным для использования этого токена, является XXX.XXX.XXX.XXX". Многие из этих политик-довольно хорошие идеи.

Firesheeping

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

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

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

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

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

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

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

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

сессия (все еще просто означает токен)

аутентификация сеанса-это просто аутентификация токена, но с несколькими различиями, которые заставляют его казаться немного другим вещь:

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

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

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

OAuth 2.0

OAuth 2.0 рассматривает проблему "как программное обеспечение a предоставляет программное обеспечение B доступ к данным пользователя X без программного обеспечения B, имеющего доступ к учетным данным пользователя X."

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

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

есть два способа, которые OAuth 2.0 может помочь вам:

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

но когда он если уж на то пошло, ты просто ... .. с помощью жетонов.

возвращаясь к вашему вопросу

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

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

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

мне 21, так что SSL-это да

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

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

основной идентификатор аутентификации / сеанса может быть украден через:

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

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

новый (более безопасный) потока:

логин

  • пользователь входит в систему и отправляет учетные данные для входа в 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. Я сожалею об этих ложных утверждениях. Однако они, кажется, работают на a стандарт JWE (JSON Web Encryption).

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

Обновлено 17.07.16:

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

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

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

легкая и ненавязчивая библиотека для реализации токенов на основе аутентификация в Эмбер.приложения на JS. http://ember-simple-auth.simplabs.com

Они имеют управление сеансом и легко подключаются в существующие проекты тоже.

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