Аутентификация для изоморфного веб-приложения с отдельными веб-сайтами и серверами API

Я разработал безстоящий API на сервере api.com. Для некоторых конечных точек API требуется аутентификация.

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

Ответ сервера также загрузит некоторый JavaScript в браузере, который впоследствии должен будет получить (через XMLHttpRequests (XHR)) некоторые данные из конечной точки API, требующие аутентификации (/tweets, например).

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

-

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

Я хочу, чтобы пользователь заходил на свои учетные данные один раз на веб-сайте.. Это похоже на текущий сайт Twitter. После входа в twitter.com сервер веб-сайта идентифицирует вас как аутентифицированный и отвечает на HTML-страницу, содержащую загрузки JavaScript. Приложение JavaScript затем (предположительно) делает аутентифицированные XHR для API без имени пользователя.

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

Как я могу это достичь? Я ищу:

  • простейшее безопасное решение
  • решение, использующее OAuth (если применимо)

Оба будут здорово!

Ответ 1

Ситуация, которую вы описываете, - именно то, для чего предназначен OAuth: клиент авторизуется с одним сервером, а затем получает доступ к ресурсам на другом сервере. В вашем случае веб-сайт является сервером авторизации, а api.com - сервером ресурсов. В двух словах сервер авторизации отправляет клиенту доступ к токену, который клиент может затем передать серверу ресурсов, чтобы доказать, что у них есть разрешение на доступ к ресурсу. Для того, чтобы это сработало, сервер ресурсов (api.com) должен либо проверить с сервера авторизации (website.com), чтобы убедиться, что токен действителен, либо заранее проинформирован о токене. Таким образом, существует треугольник связи между клиентом, сервером авторизации и сервером ресурсов, в котором передается общий секрет. Из-за этого абсолютно необходимо использовать защищенные соединения (HTTPS) во всех частях цепи; в противном случае кто-то может перехватить токен и притвориться авторизованным клиентом. Это поддерживается в разумных пределах, используя токены с ограниченным доступом, которые не полностью аутентифицируют пользователя, но тем не менее это проблема, которую вы должны попытаться предотвратить.

Теоретически, OAuth - сложная система, и ее трудно получить. Некоторые люди думают, что практически невозможно получить право (в частности, Эран Хаммер, оригинальный ведущий автор спецификации OAuth 2.0, который решил выйти из рабочей группы). Однако, учитывая, что вам все равно нужно использовать HTTPS, вы могли бы полностью отказаться от OAuth и вместо этого использовать малоизвестную встроенную функцию HTTPS (или фактически TLS), называемую аутентификацией клиента (сюрприз!).

Как вы, наверное, уже знаете, в протоколе HTTPS сервер (website.com) использует сертификат, подписанный доверенным органом, для аутентификации. Это хорошо понятный и очень безопасный механизм (по крайней мере, по интернет-стандартам), при условии, что сертификат бескомпромиссен и используется последняя версия TLS. Клиент может сделать то же самое, то есть аутентифицировать сертификат, подписанный доверенным органом. Последний орган может быть сервером (website.com) для этой цели, потому что сервер может доверять себе. Таким образом, элегантность аутентификации клиента TLS заключается в том, что клиенту не нужно обращаться к третьей стороне, чтобы получить сертификат; клиент и сервер могут взаимодействовать, чтобы предоставить клиенту сертификат, которому может доверять сервер. Это потенциально даже очень удобно, потому что сертификат клиента должен быть передан и установлен только один раз и затем может использоваться для аутентификации на последующих сеансах, возможно, без необходимости даже ввода пароля пользователем. Тот же сертификат клиента может также использоваться для соединений HTTPS с другими серверами (например, api.com), при условии, что эти серверы знают о сертификате и доверяют доверенным лицам, которые его подписали (website.com).

Аутентификация клиента TLS, вероятно, будет более безопасной, чем OAuth, в то время как для пользователя может потребоваться меньше взаимодействия с пользователем (в зависимости от способа, которым клиентский сертификат обрабатывается в браузере). С другой стороны, большинство пользователей, вероятно, не знакомы с конкретной механикой аутентификации клиента TLS. Если пользователям необходимо выполнить вход на разных устройствах или выполнить проверку подлинности на разных серверах, этот рабочий процесс может быть запутанным или громоздким, поскольку каждому устройству должен быть сертификат, и сертификат может быть выбран вручную пользователем, когда новый сервер посещается в первый раз.

Подводя итог:

  • В обоих случаях веб-сайт предоставляет клиенту возможность авторизации для доступа к api.com, о котором должен знать api.com. Так api.com не может быть 100% без гражданства; он должен иметь некоторые знания о средствах авторизации, которые веб-сайт передал с клиентом.
  • Оба случая требуют безопасного соединения (HTTPS).
  • В OAuth средством авторизации является токен ограниченного доступа с разделяемым секретом (также известный как "псевдоутверждение" ), а при аутентификации клиента TLS это закрытый сертификат, который полностью аутентифицирует клиента, поскольку он был подписан доверенный орган.
  • В OAuth авторизация выполняется на уровне данных (приложения явно передают токен доступа), в то время как при аутентификации клиента TLS аутентификация выполняется на транспортном уровне (что означает, что ваш API фактически не должен знать об аутентификации или даже авторизация, если веб-сервер настроен на то, чтобы разрешить определенные конечные точки только для аутентифицированных клиентов).
  • Аутентификация клиента TLS, вероятно, более надежна, но OAuth, вероятно, более знакома пользователям, поскольку она работает с паролями "как обычно".

Некоторые пояснения в ответ на комментарии:

Как веб-сайт знает, что пользователь вошел в систему? Как веб-сайт помнит, что пользователь вошел в систему (то есть между обновлениями браузера)?

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

Как браузер выполняет аутентифицированные запросы XHR?

Отправляя токен доступа в заголовок запроса, как и на веб-сайте. Очевидно, для этого требуется, чтобы файл cookie был доступен клиенту.

веб-сайт должен аутентифицироваться с помощью api.com при создании ответа сервера

Когда он это делает, он просто отправляет запрос (HTTPS) от имени пользователя. Это то же самое, когда токен доступа включен в заголовки запроса. На веб-сайте всегда есть токен доступа пользователя, когда он делает это, потому что он либо собирается предоставить его пользователю, либо просто получил его от пользователя.


Дополнительная информация о Википедии:

Ответ 2

Как сказал Джулиан, OAuth сложна и трудна для правильного. Я бы нашел надежный проект с открытым исходным кодом и использовал его как ваш Identity Server.

Кроме того, вместо OAuth я бы посмотрел OpenID Connect. Это относительно новый протокол (январь 2014 года), но он получает много внимания. Google+ использует его. Он объединяет структуру авторизации OAuth и добавляет структуру идентификации и аутентификации сверху. OAuth никогда не был действительно разработан для этого, что является одной из причин, по которым Эран покинул проект. Этот новый протокол - это будущее Single Sign On и заменит WS-Federation и SAML. http://openid.net/connect/

Вот все доступные текущие библиотеки: http://openid.net/developers/libraries/

Опять же, если вы используете С#/. NET, вот их проект в настоящее время в Beta 3 (должен жить в Januaray), который предоставляет все возможные конфигурируемые сценарии с примерами. Если ничего другого, он дает вам код, чтобы узнать, как его реализовать. https://github.com/thinktecture/Thinktecture.IdentityServer.v3.Samples

Смотрите этот разговор для более подробной информации: http://vimeo.com/97344501

Надеюсь, это даст вам немного еды для размышлений.

Ответ 3

Я думаю, что что-то подобное можно сделать

1) Пользователь регистрируется на веб-сайте website.com, веб-сайт создаст временный токен T для использования в будущем API

2) Всякий раз, когда некоторые данные требуются с api.com, веб-сайт запрашивает эти данные и отправляет токен T в запрос api.com/getdata/params =... & токен = T

Этот запрос лучше сделать с SSL для защиты токена.

Также проверьте http://en.wikipedia.org/wiki/Cross-origin_resource_sharing - не все браузеры позволят вам запрашивать данные из другого домена из Javascript.

3) Когда api.com получит такой запрос, он сделает отдельное и секретное соединение с веб-сайтом, что-то вроде website.com/checktoken/?token=T и получит всю необходимую информацию о пользователе на веб-сайте. com, чтобы отправить ему соответствующие данные

4) Пользователь получает всю информацию, не покидая website.com и не должен проходить аутентификацию в двух местах.

Ответ 4

В принципе, вам нужно решить, хотите ли вы разрешать домен веб-сайта использовать методы api.com или разрешать пользователям веб-сайта использовать api.com. Из вашего описания я понимаю, что вы говорите о втором случае.

Тогда какая-то реализация OAuth (OAuth2.0) может быть подходящей для вас (возможно) для одной точки аутентификации для всех ваших сайтов: это может быть паспорт .com. Когда пользователь хочет использовать api.com или website.com или любой другой ваш сайт, он будет перенаправлен на паспорт .com и должен пройти аутентификацию. После аутентификации на сайте паспорт .com пользователь будет перенаправлен обратно и предоставлен код авторизации, который используется для запроса токена, который, в свою очередь, может быть использован api.com и website.com для получения информации о пользователе (роли, разрешения и т.д.). На сайте website.com вы можете использовать этот токен для доступа к api.com, потому что api.com может использовать этот токен для проверки пользователя на сайте passport.com. Также вы можете использовать этот токен, чтобы запрашивать информацию с api.com by AJAX (однако вам нужно преодолеть одну и ту же проблему с исходной политикой, но это возможно).

UPDATE:

Идея заключается в том, что пользователь должен быть аутентифицирован на сайте passport.com для использования website.com и api.com. С точки зрения OAuth2.0 вы можете сказать, что пользователь разрешает website.com и api.com использовать свою информацию на паспорте .com. Таким образом, cookie аутентификации существует только для домена passport.com и не отправляется нигде (на сайт .com или api.com). Это соответствует той же политике происхождения.

Таким образом, более подробное описание реализации OAuth2.0 в вашем случае будет:

  • Пользователь хочет (или должен) быть аутентифицированным на веб-сайте. Запрос на паспорт .com выполняется (с указанным REDIRECT_URL на веб-сайте, где позже): passport.com/auth/?redirectTo=REDIRECT_URL

    Если пользователь не прошел проверку подлинности на паспорте .com(там нет файла cookie Auth), то ему открывается страница loginpass.com. При аутентификации новый AUTHORIZATION_CODE сохраняется на паспорт .com(в базе данных) для этого пользователя.

  • После аутентификации на сайте passport.com(или если пользователь уже был аутентифицирован там), паспорт .com перенаправляет пользователя обратно в REDIRECT_URL с помощью AUTHORIZATION_CODE в querystring: {REDIRECT_URL}? code = AUTHORIZATION_CODE

  • Website.com использует этот AUTHORIZATION_CODE для запроса ACCESS_TOKEN на паспорт .com: passport.com/token/?code=AUTHORIZATION_CODE

  • Имея ACCESS_TOKEN, веб-сайт может использовать его для запроса информации о пользователе с сайта passport.com. Кроме того, вы можете передать этот ACCESS_TOKEN на api.com при запросе чего-либо с api.com. api.com может проверить идентификацию пользователя на паспорт .com, чтобы проверить, есть ли у него достаточно разрешений. Безопасно ли передавать ACCESS_TOKEN на api.com? Вам нужно предоставить какой-то ключ api.com в любом случае (если api.com не является общедоступным api), поэтому, используя этот подход, по крайней мере ACCESS_TOKEN не является статическим: он имеет время жизни и основан на пользователе.

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

Ответ 5

Вот простой способ. Он добавляет некоторые накладные расходы/задержки, но по крайней мере он работает и прост:

позволить веб-сайту действовать как прокси-сервер и перенаправлять все вызовы на api.com

browser <-> https://website.com/api/url <-> https://api.com/url

Вы можете просто повторно использовать кредитные ресурсы, чтобы сделать отдельный сеанс с сайта website.com на api.com