![](https://habrastorage.org/files/468/40f/d54/46840fd544d2494092b1855da29b3a32.png)
Автор: Вячеслав Михайлов, Solutions Architect
Это вводная часть материала, основанного на докладе, прочитанном мной прошлым летом. Печатный материал предполагает больше информации, т.к. в одном докладе обычно не получается рассказать обо всех деталях.
Мы разберемся с процессом аутентификации пользователя, работой технологии единого входа (Single sign-on/SSO), дадим общее представлении о технологии OAuth2 и принципах ее работы, не углубляясь в особенности конкретной технической реализации. В следующей статье в качестве примера удачной реализации мы рассмотрим библиотеку Thinktecture Identity Server v3, подробнее остановимся на ее функциональных возможностях, поговорим, как собрать минимальный набор компонент, необходимый для работы в микросервисной архитектуре и достойный использования в боевой системе. В третьей части мы покажем, как расширять эту библиотеку, подстраиваясь под нужды вашей системы, а завершит цикл статей разбор различных сценариев, встречавшихся в жизни многих разработчиков с рекомендациями для каждого случая.
Что такое аутентификация?
На процессах аутентификации и авторизации основано разделения прав доступа, без которого не обходится ни одно более или менее серьезное приложение. Поэтому понимать, как они происходили раньше и происходят теперь, очень важно, но, прежде чем углубиться в описание технологии, давайте разберемся с ключевыми терминами.
Идентификация — процесс определения, что за человек перед нами. Аутентификация — процесс подтверждения, что этот человек именно тот, за кого себя выдает. Авторизация — процесс принятия решения о том, что именно этой аутентифицированной персоне разрешается делать. То есть, это три разных, последовательных и взаимно не заменяемых понятия. Идентификацию часто подразумевают в составе аутентификации. Самое главное — четко различать аутентификацию и авторизацию.
В ходе аутентификации мы удостоверяемся, что человек, который к нам пришел, обладает доказательствами, подтверждающими личность. В этой статье речь в основном пойдет как раз об аутентификации.
Способы аутентификации
При использовании HTTP-протокола простейший способ аутентификации — Basic access authentication. В принципе этот протокол устарел и уже редко используется в интернете, особенно в незащищенных соединениях, но еще сохраняется во внутрикорпоративных системах, просто потому что некоторые из них созданы достаточно давно. Стоит разобраться, как он работает.
HTTP Basic Authentication
![Picture1](https://habrastorage.org/getpro/habr/post_images/23a/fa1/dc4/23afa1dc47066c01e26406efaa5072f0.png)
Первым, что при обращении к защищенному ресурсу сервер выдаст пользователю, не имеющему доступа, будет ошибка 401 Unauthorized. При этом ответ также содержит информацию о типе аутентификации (в нашем случае – Basic), который он может принимать, и контекст, в рамках которого эта аутентификация действует (Realm). Пользователь вводит логин и пароль, они упаковываются в Base64 и отправляются на сервер для проверки. Здесь существуют различные опасности. Самая распространенная — угроза man-in-the-middle attack, или атаки посредника, в ходе которой при использовании незащищенного соединения учетные данные могут перехватить злоумышленники в момент передачи от клиента к серверу или обратно.
HTTP Digest Authentication
![](https://habrastorage.org/getpro/habr/post_images/3fa/2cc/54e/3fa2cc54e662f9cf0c48e24b869fa9c3.png)
Следующим этапом развития технологии стала чуть более сложная система HTTP digest authentication, которая исключает передачу учетных данных в открытом виде — здесь для проверки используется MD5-хеш с некоторыми примесями, что позволяет избежать подбора логина и пароля. Конечно, этот алгоритм выглядит более надежным, но и он подвержен целому ряду не самых сложных атак. Например, вот тут можно почитать об атаках более подробно.
Forms Authentication
![](https://habrastorage.org/getpro/habr/post_images/626/8fb/ab5/6268fbab585e76307c370d37d33088d3.png)
Позднее появился процесс Forms authentication, при котором аутентификация происходит на более высоком уровне модели абстракции. HTTP-сервер при этом не сообщает об ошибке доступа, а просто перенаправляет неаутентифицированного пользователя на другую страницу. Обычно на этой странице отображаются поля для ввода логина и пароля, после заполнения которых формируется POST-запрос с данными и через защищенный канал направляется на сервер. Серверная сторона в свою очередь возвращает пользователю токен или идентификатор сессии, который сохраняется в Cookies и в дальнейшем используется для доступа к защищенному ресурсу.
Token Authentication
![](https://habrastorage.org/getpro/habr/post_images/893/3cb/7ff/8933cb7ffab0879431fcc56b5d6bf47d.png)
Следующее поколение способов аутентификации представляет Token Based Authentication, который обычно применяется при построении систем Single sign-on (SSO). При его использовании запрашиваемый сервис делегирует функцию проверки достоверности сведений о пользователе другому сервису. Т. е. провайдер услуг доверяет выдачу необходимых для доступа токенов собственно токен-провайдеру (Identity provider). Это то, что мы видим, например, входя в приложения через аккаунты в социальных сетях. Вне IT самой простой аналогией этого процесса можно назвать использование общегражданского паспорта. Официальный документ как раз является выданным вам токеном — все государственные службы по умолчанию доверяет отделу полиции, который его вручил, и считает паспорт достаточным для вашей аутентификации на протяжении всего срока действии при сохранении его целостности.
На схеме хорошо видно, как и в какой последовательности приложения обмениваются информацией при использовании аутентификацией по токенам.
![](https://habrastorage.org/getpro/habr/post_images/c91/052/760/c9105276000186a491f20131c1e8ad5c.png)
На следующей схеме дополнительно отражены те этапы взаимодействия, в которых пользователь принимает непосредственное участие. Этот момент и является недостатком подобной схемы — нам всегда нужен пользователь, чтобы получить доступ к ресурсу.
![](https://habrastorage.org/getpro/habr/post_images/8aa/2b5/6d4/8aa2b56d411886a0e5e37b6fcd091ab5.png)
OAuth2 & Open ID Connect
Дальнейшее усовершенствование процесса понадобилось ввиду того, что токен-аутентификация требует присутствия пользователя в момент получения доступа к защищенному ресурсу. Потому что Identity provider при передаче ему управления будет с пользователем взаимодействовать, запрашивая, например, логин и пароль.
В случае сервиса, который от имени пользователя должен через определенные промежутки времени опрашивать некий третий ресурс, — допустим, получать доступ к списку контактов в социальной сети — токен-аутентификация работать уже не будет. Дело в том, что идентификаторы сессии обычно живут очень недолго, чтобы в случае их перехвата злоумышленники получили доступ к сервису лишь на ограниченное время. Но из-за короткого срока действия токена не хватает, например, на ночной процесс.
В 2006 году в ходе работы над реализацией протокола Open ID для Twitter обнаружилась потребность в новом открытом протоколе авторизации. В 2007 инженеры Google и AOL начали совместную работу над ним, а в 2009 Twitter предложил своим пользователям решение, делегировавшее сторонним сервисам доступ к аккаунтам и основанное на протоколе OAuth. Три года спустя была опубликована новая версия — OAuth 2, упростившая разработку клиентских приложений и получившая целый ряд новых возможностей, среди которых оказалось и обновление токена без участия пользователя. Многие сервисы начали использовать этот протокол еще до его официального утверждения.
Разбираемся детально ху из ху
В данный момент на слуху следующие протоколы:
- OpenID — для проверки учетных данных пользователя (identification & authentication).
- OAuth — про то, чтобы получать доступ к чему-то.
- OpenID Connect — и про и то, и про другое одновременно.
Все три протокола позволяют пользователю не разглашать свои секретные логин и пароль недоверенным приложениям. OpenID & OAuth разрабатывались параллельно вплоть до 2014 года и объединились в итоге в OpenID connect.
OpenID 1.0 (2006) & OpenID 2.0 (2007) позволяли приложению(арб) запрашивать у доверенного сервера (authority) проверку пользователя(user). Отличия между версиями для нас несущественны.
- User –> App: Привет, это Миша.
- App –> Authority: Вот «это» Миша?
- Authority и User общаются тет-а-тет.
- Authority –> App: Да, это Миша.
OpenID Attribute Exchange 1.0 (2007) расширяет OpenID 2.0 разрешая получать и хранить профиль пользователя.
- User –> App: Привет, это Миша.
- App –> Authority: Вот «это» Миша? И если это Миша, то пришлите мне его email.
- Authority и User общаются тет-а-тет.
- Authority –> App: Да, это Миша. И его email xxx@xxx.xxx.
OAuth 1.0 (2010) позволяет пользователю разрешать приложению получать ограниченный доступ на третьесторонних серверах(third-party server), доверяющих удостоверяющему центру.
- App –> User: Mы бы хотели получить ваши картинки с другого сервера.
- Authority и User общаются тет-а-тет.
- Authority –> App: Вот вам билет (access token) на 15 минут.
- App –> Third-party server: Нам тут по билету можно получить фотографии для этого пользователя.
OAuth 2.0 (2012) делает тоже самое, что и OAuth 1.0, но только протокол существенно поменялся и стал проще.
OpenID Connect (2014) объединяет возможности OpenID 2.0, OpenID Attribute Exchange 1.0, и OAuth 2.0 в один общий протокол. Он позволяет приложениям использовать удостоверяющий центр для:
- Проверять учетные данные пользователя.
- Получать профиль пользователя (или его части).
Важно понимать, что OpenID Connect не дает доступ к внешним ресурсам. Он использует OAuth 2.0 для того, чтобы представить параметры профиля как будто это такие ресурсы.
Взгляд сверху
![Picture7](https://habrastorage.org/getpro/habr/post_images/2a9/8e8/d1a/2a98e8d1a542f955eb15c0bb7f4ffec4.png)
Обычно в системах встречаются разные компоненты: пользователи, работающие через браузер, пользователи, взаимодействующие с сервером через мобильные приложения, и просто серверные приложения, нуждающиеся в принадлежащих вам данных, хранящихся на других серверах, доступ к которым осуществляется через Web API.
Single sign-on — технология единого входа — позволяет пользователю переключаться между различными приложениями без повторной аутентификации. Используя SSO можно избежать множественных логинов, так что пользователь просто не будет замечать этих переключений. При этом ситуации, когда в рамках вашей инфраструктуры таких приложений будет больше одного, встречаются постоянно. Технология единого входа особенно удобна в больших энтерпрайз-системах, состоящих из десятков приложений, слабо связанных между собой. Вряд ли пользователи будут довольны, вводя логин и пароль при каждом обращении к системе учета рабочего времени, корпоративному форуму или внутренней базе документов.
В качестве реализации мы рассматриваем протокол OAuth2. В принципе, существуют и другие, например, Kerberos, успешно взаимодействующий с Windows, но в случае гетерогенной сети, в которой существуют компьютеры, использующие и Windows-, и Mac-, и UNIX-системы, использовать проприетарные протоколы зачастую неудобно. Тем более, это касается случаев, когда доступ к вашим сервисам осуществляется через веб — здесь OAuth2 оказывается лучшим кандидатом.
![Picture8](https://habrastorage.org/getpro/habr/post_images/bc9/ad8/618/bc9ad86182b31533cc26413abc67924f.png)
На рисунке выше показано, какие именно протоколы используются при каждом типе взаимодействия.
Как мы знаем из раздела «разбираемся детально ху из ху», OpenID Сonnect нужен, чтобы получить у пользователя его учетные данные и проверить их. OAuth 2.0 нужен, чтобы получать токены доступа и с ними обращаться к ресурсам.
Терминология OAuth2 & OpenID Connect
- OpenID Connect Provider (OP)
- Client
- User
- Scope
- Identity scopes – openid, profile, email
- Resource scopes – various API
- Authentication/Token Request
- Identity Token
- Access Token
- Refresh Token
Сервис выдачи токенов
Open ID Connect Provider — важнейший объект всей конструкции централизованного сервиса аутентификации, он также может называться Security Token Service, Identity Provider authorization server и т. д. Различные источники называют его по-разному, но по смыслу это сервис, который выдает токены клиентам.
Основные функции:
- Аутентифицировать пользователей, используя внутреннее хранилище пользователей или внешний источник (например, Active Directory).
- Управлять клиентами (хранить) и аутентифицировать их.
- Предоставлять управление сессией и возможность реализации Single sing-on.
- Выдавать identity-токены и access-токены клиентам.
- Проверять ранее выданные токены.
Клиент
Client — устройство или программа (браузер, приложение), которым требуется либо токен для аутентификации пользователя, либо токен для доступа к какому-то ресурсу (подразумевается, что данный ресурс «знаком» с тем конкретным «Security Token Service» у которого клиент запрашивает токен для доступа).
Пользователь
User — собственно конечный пользователь — человек.
Область (scope)
Scope — идентификатор ресурса, к которому клиент хочет получить доступ. Список scope посылается в адрес сервиса выдачи токенов в составе запроса на аутентификацию.
По умолчанию все клиенты имеют возможность запрашивать любые области, но это можно (и нужно) ограничивать в конфигурации сервиса выдачи токенов.
Scopes бывают двух видов:
- Identity scopes — это запрос информации о пользователе. Его имя, профиль, пол, фотография, адрес электронной почты и т. д.
- Resource scopes — имена внешних ресурсо (Web APIs), к которым клиент хочет получить доступ.
Запрос на аутентификацию
Authentication/Token Request — процесс запроса аутентификации.
В зависимости от того какие области (scopes) запрошены, сервис выдачи токенов вернет:
- Только Identity Token, если запрошены только Identity scopes.
- Identity Token и Access Token, если запрошены также и Resources scopes.
- Access Token и Refresh Token, если запрошeн Offline Access.
Более подробно про процесс аутентификации можно прочесть в разделе «процесс aутентификации».
Токен личности
Identity Token — подтверждение аутентификации. Этот токен содержит минимальный набор информации о пользователе.
Токен доступа
Access Token — информация, что конкретному пользователю разрешается делать. Клиент запрашивает Access Token и затем использует его для доступа к ресурсам (Web APIs). Access Token содержит информацию о клиенте и пользователе, если она присутствует. Важно понимать, что есть такие типы авторизации, при которых пользователь в процессе непосредственно не участвует (подробнее об этом в следующей части)
Токен обновления
Refresh Token — токен, по которому STS вернет новый Access Token. В зависимости от режима работы, Refresh Token может быть многоразовым и одноразовым. В случае с одноразовым токеном, при запросе нового Access Token будет также сформирован готовый Refresh Token, который следует использовать при повторном обновлении. Очевидно, что одноразовые токены более безопасны.
Более подробно о составе токенов в разделе «структура токена».
Процесс аутентификации
![Picture9](https://habrastorage.org/getpro/habr/post_images/c13/afc/ee5/c13afcee5226ddb135df9836d3321b17.png)
При обращении пользователя к клиенту, тот перенаправляет пользователя на Open ID Connect Provider, который запрашивает у пользователя логин и пароль. В случае успешного прохождения проверки параметров аутентификации он возвращает назад identity token и access token, с которыми пользователь может обращаться к защищенному ресурсу.
Структура токена
Формат
![Picture10](https://habrastorage.org/getpro/habr/post_images/27d/f7e/0a3/27df7e0a35dc2e8c48833646beff13b9.png)
В реализации OAuth2 используется так называемый jwt-токен, который состоит из трех частей. Допустим, при обращении к Identity provider вы отправляете логин/пароль и в ответ получаете токен. Он будет включать в себя: Header (заголовок), Payload (контент) и Signature (подпись). На сайте jwt.io его можно декодировать и посмотреть содержимое формате JSON. На этом сайте вы также найдете описание правил формирования jwt-токенов.
В том, что токены в процессе обмена передаются незашифрованными, ничего страшного нет. Мы изначально исходим из предположения, что коммуникация происходит по защищенному HTTPS-каналу, и повторное шифрование токена было бы избыточным. Единственное, в чем нам нужно убедиться – то, что токен не был подменен или сфальсифицирован на клиентской стороне, для этого достаточно иметь подпись и проверять ее на сервере. Кроме того, токен не содержит никакой критически важной информации.
Кроме identity tokens, есть еще и аccess tokens, которые содержат информацию о выданных пользователю клеймах. Срок действия access token достаточно короткий, потому что его хищение может обеспечить несанкционированный доступ к ресурсу. Т. е. злоумышленник, если ему удастся заполучить токен этого типа, доступ получит на очень непродолжительное время. Для получения нового access token используется refresh token, который обычно не фигурирует в незащищенных средах, в частности в режиме доступа из браузера он вообще не используется. Какие именно токены будут возвращены клиенту в процессе аутентификации, разберемся в следующей части.
Основные поля
Кратко остановимся на том, какие есть стандартные полях в токене и зачем они нужны:
- iss — адрес или имя удостоверяющего центра.
- sub — идентификатор пользователя. Уникальный в рамках удостоверяющего центра, как минимум.
- aud — имя клиента для которого токен выпущен.
- exp — срок действия токена.
- nbf — время, начиная с которого может быть использован (не раньше чем).
- iat — время выдачи токена.
- jti — уникальный идентификатор токен (нужен, чтобы нельзя был «выпустить» токен второй раз).
Заключение первой части
В этой статье мы постарались дать теоретический и терминологический фундамент, который понадобится нам создании работающего решения в следующих статьях.
Stay tuned.
public void Configuration(IAppBuilder app)
{
var factory = new IdentityServerServiceFactory();
factory.UseInMemoryClients(Clients.Get())
.UseInMemoryScopes(Scopes.Get())
.UseInMemoryUsers(Users.Get());
var options = new IdentityServerOptions
{
SiteName = Constants.IdentityServerName,
SigningCertificate = Certificate.Get(),
Factory = factory,
};
app.UseIdentityServer(options);
}
Минимальная реализация интеграции веб-клиента с Identity Server:
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = Constants.ClientName,
Authority = Constants.IdentityServerAddress,
RedirectUri = Constants.ClientReturnUrl,
ResponseType = "id_token",
Scope = "openid email",
SignInAsAuthenticationType = "Cookies",
});
}
Минимальная реализация интеграции веб-API с Identity Server:
public void Configuration(IAppBuilder app)
{
app.UseIdentityServerBearerTokenAuthentication(
new IdentityServerBearerTokenAuthenticationOptions
{
Authority = Constants.IdentityServerAddress,
RequiredScopes = new[] { "write" },
ValidationMode = ValidationMode.Local,
// credentials for the introspection endpoint
ClientId = "write",
ClientSecret = "secret"
});
app.UseWebApi(WebApiConfig.Register());
}
Комментарии (12)
nkochnev
30.09.2016 00:41-1У нас своя реализация протокола OAuth 2.0 для авторизации в десятке внутренних и внешних веб-приложений.
В понедельние в компанию приходит новый сотрудник, пусть по этой статье изучает теорию :) Надоело самому объяснять. От души спасибо!whirl
30.09.2016 10:11+2И она полность соответствет RFC 6749 и OpenID Connect?
nkochnev
30.09.2016 11:34Нет. Различия безусловно есть. Некоторые моменты опускались, но не в ущерб безопасности. Например, структура токена
vmikhaylov
30.09.2016 11:43+2Реализация собственных баз данных, операционных систем, протоколов шифрования, аутентификации и авторизации несет существенные риски и редко обосновано. Такое решение должно быть обязательно взвешенным, чтобы потом не разгребать «детские болезни» путем финансовых потерь проекта.
nkochnev
30.09.2016 11:47Согласен, но в момент принятия решения о реализации не было найдено подходящего «фреймворка».
Было бы страшнее, если бы мы придумали свой «стандарт» OAuth 3.0 :)
BigD
30.09.2016 10:13-1Не упомянули SAML, фактически являющийся стандартом для enterprise веб приложений и cloud сервисов.
vmikhaylov
30.09.2016 10:32+1Я не считаю его перспективным протоколом, а потому и не включил в вводную часть.
BigD
30.09.2016 22:46Почему? Мы сейчас все приложения на SAML 2.0 переводим в рамках реализации SSO стратегии. Тысячи приложений, hosted/cloud. Что с ним не так?
vmikhaylov
01.10.2016 00:33+2Начнем с того что это XML ) Размер токена ощутимо больше даже при томе же объеме информации.
Его нельзя положить в query string. Там куча разных параметром шифрования которые не факт, что нужны.
Зачем использовать что-то более сложное, если есть простое и надежное решение?
x512
Отличная статья! Есть пожелание использовать для примеров Identity Server 4 у которого уже вышел первый релиз-кандидат и подробнее рассмотреть авторизацию и аутентификацию в клиентских SPA.
vmikhaylov
Обязательно в другой раз. Сейчас хочется рассказать о том, что можно надежно использовать в продакшене.