Аутентификация и авторизацияvна PHP
Предопределённые PHP переменные
Basic HTTP Authentication
Чтобы создать проверку пользователя во всплывающем окне достаточно следующего кода:
Тем не менее, желательно добавить немного функционала:
В Firefox это Library → History → Clear Recent History → Active Logins
В Chrome это Passwords and other sing-in data (в Clear browsing data → Advanced)
В Safari это Clear History
Если пароль поменялся, пользователя со старым паролем не выкинет и т.д.
Примечание о совместимости
Пожалуйста, будьте осторожны при кодировании строк заголовка HTTP.
Чтобы гарантировать максимальную совместимость со всеми клиентами, ключевое слово «Basic» должно быть написано с прописной буквой «B», строка realm должна быть заключена в двойные (а не одинарные) кавычки, и ровно один пробел должен предшествовать коду 401 в строке заголовка HTTP/1.0 401. Параметры аутентификации должны быть разделены запятыми, как показано в приведенном выше примере дайджеста.
Очистить глобальные переменные
HTTP Digest Authentication
Дайджест-аутентификация доступа — один из общепринятых методов, используемых веб-сервером для обработки учетных данных пользователя веб-браузера.
Аналогичный метод используется в рамках VoIP-протокола SIP для аутентификации сервером обращения со стороны клиента, т.е. оконечного терминала.
Данный метод отправляет по сети хеш-сумму логина, пароля, адреса сервера и случайных данных, и предоставляет больший уровень защиты, чем базовая аутентификация, при которой данные отправляются в открытом виде.
Технически, аутентификация по дайджесту представляет собой применение криптографической хеш-функции MD5 к секрету пользователя с использованием случайных значений для затруднения криптоанализа и предотвращения replay-атак. Работает на уровне протокола HTTP.
Это более продвинутый вариант HTTP Аутентификации.
Можно использовать следующие опции ( полный список в RFC )
Необязательный список URI (через пробел), которые защищены данным запросом на аутентификацию.
algorithm
Указывает на алгоритм, используемый для создания дайджеста.
opaque
base64 или HEX строка которую генерирует сервер. Клиент должен вернуть opaque неизменённым.
nonce должен быть в одинарных кавычках (не в двойных)
stale
Флаг, который показывает на то, что предыдущий запрос от клиента был отклонён из за того, что значение nonce было несвежим.
Сервер должен ставить флаг stale в TRUE (регистронечувствительный) если пароль и имя пользователя верные и только nonce устарел.
В этом случае клиент может попытаться отправить ещё один зашифрованный запрос не запрашивая у пользователя ввод пароля.
Если сервер отказал в соединении а stale поставлен в FALSE, либо любое значение кроме TRUE, либо вообще отсутствует, значит клиент должен запросить логин и пароль снова.
Опция для HTTP Digest Authentication. Может принимать значения «auth» или «auth-int». Влияет на то как создается хэш.
Если поставить в «auth» будет использоваться только запрошенный URI. Если в «auth-int» то также будет использовано тело запроса.
Обзор Digest Аутентификации
WWW-Authenticate: Digest realm=»AndreiR»,
qop=»auth,auth-int»,
nonce=»abcdefg…»,
opaque=»abcd…»,
HA1 = MD5 хэш из имени пользователя, пароля и строки realm.
HA2 = MD5 хэш из метода аутентификации и запрошенного URI
Response = MD5 хэш из HA1, HA2, nonce, nonce-count, cnonce и qop
Клиент отправляет новый запрос на основе сгенерированных данных
GET /
Authorization: Digest username=»andrei», realm=»AndreiR», uri=»/»
qop=auth, nc=00000001,response=»12345abc…»
nonce=»abcdefg…»,
opaque=»abcd…»,
Некоторые опции необязательны, поэтому гарантировать определённый уровень безопасности нельзя.
HTTP Digest Аутентификация уязвима для атак посредника (MITM) так как сервер не может проверить идентичность клиента.
Невозможно использовать более сложные алгоритмы хэширования паролей, такие как bcrypt
Аутентификация и авторизацияvна PHP
Предопределённые PHP переменные
Basic HTTP Authentication
Чтобы создать проверку пользователя во всплывающем окне достаточно следующего кода:
Тем не менее, желательно добавить немного функционала:
В Firefox это Library → History → Clear Recent History → Active Logins
В Chrome это Passwords and other sing-in data (в Clear browsing data → Advanced)
В Safari это Clear History
Если пароль поменялся, пользователя со старым паролем не выкинет и т.д.
Примечание о совместимости
Пожалуйста, будьте осторожны при кодировании строк заголовка HTTP.
Чтобы гарантировать максимальную совместимость со всеми клиентами, ключевое слово «Basic» должно быть написано с прописной буквой «B», строка realm должна быть заключена в двойные (а не одинарные) кавычки, и ровно один пробел должен предшествовать коду 401 в строке заголовка HTTP/1.0 401. Параметры аутентификации должны быть разделены запятыми, как показано в приведенном выше примере дайджеста.
Очистить глобальные переменные
HTTP Digest Authentication
Дайджест-аутентификация доступа — один из общепринятых методов, используемых веб-сервером для обработки учетных данных пользователя веб-браузера.
Аналогичный метод используется в рамках VoIP-протокола SIP для аутентификации сервером обращения со стороны клиента, т.е. оконечного терминала.
Данный метод отправляет по сети хеш-сумму логина, пароля, адреса сервера и случайных данных, и предоставляет больший уровень защиты, чем базовая аутентификация, при которой данные отправляются в открытом виде.
Технически, аутентификация по дайджесту представляет собой применение криптографической хеш-функции MD5 к секрету пользователя с использованием случайных значений для затруднения криптоанализа и предотвращения replay-атак. Работает на уровне протокола HTTP.
Это более продвинутый вариант HTTP Аутентификации.
Можно использовать следующие опции ( полный список в RFC )
Необязательный список URI (через пробел), которые защищены данным запросом на аутентификацию.
algorithm
Указывает на алгоритм, используемый для создания дайджеста.
opaque
base64 или HEX строка которую генерирует сервер. Клиент должен вернуть opaque неизменённым.
nonce должен быть в одинарных кавычках (не в двойных)
stale
Флаг, который показывает на то, что предыдущий запрос от клиента был отклонён из за того, что значение nonce было несвежим.
Сервер должен ставить флаг stale в TRUE (регистронечувствительный) если пароль и имя пользователя верные и только nonce устарел.
В этом случае клиент может попытаться отправить ещё один зашифрованный запрос не запрашивая у пользователя ввод пароля.
Если сервер отказал в соединении а stale поставлен в FALSE, либо любое значение кроме TRUE, либо вообще отсутствует, значит клиент должен запросить логин и пароль снова.
Опция для HTTP Digest Authentication. Может принимать значения «auth» или «auth-int». Влияет на то как создается хэш.
Если поставить в «auth» будет использоваться только запрошенный URI. Если в «auth-int» то также будет использовано тело запроса.
Обзор Digest Аутентификации
WWW-Authenticate: Digest realm=»AndreiR»,
qop=»auth,auth-int»,
nonce=»abcdefg…»,
opaque=»abcd…»,
HA1 = MD5 хэш из имени пользователя, пароля и строки realm.
HA2 = MD5 хэш из метода аутентификации и запрошенного URI
Response = MD5 хэш из HA1, HA2, nonce, nonce-count, cnonce и qop
Клиент отправляет новый запрос на основе сгенерированных данных
GET /
Authorization: Digest username=»andrei», realm=»AndreiR», uri=»/»
qop=auth, nc=00000001,response=»12345abc…»
nonce=»abcdefg…»,
opaque=»abcd…»,
Некоторые опции необязательны, поэтому гарантировать определённый уровень безопасности нельзя.
HTTP Digest Аутентификация уязвима для атак посредника (MITM) так как сервер не может проверить идентичность клиента.
Невозможно использовать более сложные алгоритмы хэширования паролей, такие как bcrypt
HTTP-аутентификация в PHP
Пример фрагмента скрипта, который вынуждает клиента авторизоваться для просмотра страницы:
Пример #1 Пример Basic HTTP-аутентификации
Пример #2 Пример Digest HTTP-аутентификации
Это пример реализации простого скрипта Digest HTTP-аутентификации. За подробностями обращайтесь к » RFC 2617.
die( ‘Текст, отправляемый в том случае, если пользователь нажал кнопку Cancel’ );
>
Замечание: Замечание касательно совместимости
Будьте особенно внимательны при указании HTTP-заголовков. Для того, чтобы гарантировать максимальную совместимость с наибольшим количеством различных клиентов, слово «Basic» должно быть написано с большой буквы «B», регион (realm) должен быть взят в двойные (не одинарные!) кавычки, и ровно один пробел должен предшествовать коду 401 в заголовке HTTP/1.0 401. Параметры аутентификации должны разделяться запятыми, как это было показано в примере Digest аутентификации выше.
Вы можете пронаблюдать особенности работы браузера Internet Explorer. Он очень требователен к параметру передаваемых заголовков. Трюк с указанием заголовка WWW-Authenticate перед отправкой статуса HTTP/1.0 401 пока что работает для него.
Замечание: Замечание касательно конфигурации
PHP использует указание директивы AuthType для указания того, используется внешняя аутентификация или нет.
Следует заметить, что все вышесказанное не предотвращает похищения паролей к страницам, требующим авторизацию, кем-либо, кто контролирует страницы без авторизации, расположенные на том же сервере.
И Netscape Navigator и Internet Explorer очищают кеш аутентификации текущего окна для заданного региона (realm) при получении от сервера статуса 401. Это может использоваться для реализации принудительного выхода пользователя и повторного отображения диалогового окна для ввода имени пользователя и пароля. Некоторые разработчики используют это для ограничения авторизации по времени или для предоставления кнопки «Выход».
Пример #3 Пример HTTP-аутентификации с принудительным вводом новой пары логин/пароль
function authenticate () <
header ( ‘WWW-Authenticate: Basic realm=»Test Authentication System»‘ );
header ( ‘HTTP/1.0 401 Unauthorized’ );
echo «Вы должны ввести корректный логин и пароль для получения доступа к ресурсу \n» ;
exit;
>
Для того, чтобы добиться корректной работы HTTP-аутентификации в IIS сервере с CGI версией PHP, вы должны отредактировать конфигурационную настройку IIS под названием » Directory Security «. Щёлкните на надписи » Edit » и установите опцию » Anonymous Access «, все остальные поля должны остаться неотмеченными.
Замечание: Замечание касательно IIS:
Для того, чтобы HTTP-аутентификация корректно работала в IIS, в конфигурации PHP-опция cgi.rfc2616_headers должна быть установлена значением 0 (значение по умолчанию).
User Contributed Notes 46 notes
Workaround for missing Authorization header under CGI/FastCGI Apache:
This is the simplest form I found to do a Basic authorization with retries.
// If arrives here, is a valid user.
echo «
Congratulation, you are into the system.
In case of CGI/FastCGI you would hot be able to access PHP_AUTH* info because CGI protocol does not declare such variables (that is why their names start from PHP) and server would not pass them to the interpreter. In CGI server should authenticate user itself and pass REMOTE_USER to CGI script after it.
So you need to «fetch» request headers and pass them to your script somehow.
In apache you can do it via environment variables if mod_env is installed.
SetEnvIfNoCase ^Authorization$ «(.+)» PHP_AUTH_DIGEST_RAW=$1
Do not forget to strip auth type («Digest» in my case) from your env variable because PHP_AUTH_DIGEST does not have it.
If mod_env is not installed you probably have mod_rewrite (everyone has it because of «human readable URLs»).
You can fetch header and pass it as GET parameter using rewrite rule:
RewriteRule ^.*$ site.php?PHP_AUTH_DIGEST_RAW=%
—
If you use ZF you probably use Zend_Auth_Adapter_Http to auth user.
[NOTE BY danbrown AT php DOT net: The following note was added by «Anonymous» on 01-APR-2010 (though we presume it’s not an April Fool’s Day joke).]
this logout method does not work 100% anymore, because of another bulls**t from M$:
http://support.microsoft.com/kb/834489
Some servers won’t support the HTTP1.0 specification and will give an error 500 (for instance). This happened with a server where I uploaded an authentication script.
If it happens, you can try the HTTP1.1 header syntax :
( «WWW-Authenticate: Basic realm=\»My Realm\»» );
header ( ‘status: 401 Unauthorized’ );
?>
Be careful using http digest authentication (see above, example 34.2) if you have to use the ‘setlocale’ function *before* validating response with the ‘http_digest_parse’ function, because there’s a conflict with \w in the pattern of ‘preg_match_all’ function :
In fact, as \w is supposed to be any letter or digit or the underscore character, you must not forgot that this may vary depending on your locale configuration (eg. it accepts accented letters in french).
Due to this different pattern interpretation by the ‘preg_match_all’ function, the ‘http_digest_parse’ function will always return a false result if you have modified your locale (I mean if your locale accepts some extended characters, see http://fr.php.net/manual/en/reference.pcre.pattern.syntax.php for further information).
IMHO, I suggest you not to use setlocale before having your authentication completed.
PS : Here’s a non-compatible setlocale declaration.
setlocale ( LC_ALL, ‘fr_FR’, ‘fr’, ‘FR’, ‘french’, ‘fra’, ‘france’, ‘French’, ‘fr_FR.ISO8859-1’ ) ;
you have logged!
Note that Microsoft has released a ‘security update’ which disables the use of username:password@host in http urls.
The methods described above which rely on this will no longer work in Microsoft browsers, sadly.
You can re-enable this functionality as described at
but your users will probably be unwilling to do this.
I came up with another approach to work around the problem of browsers caching WWW authentication credentials and creating logout problems. While most browsers have some kind of way to wipe this information, I prefer having my website to take care of the task instead of relying on the user’s sanity.
Even with Lalit’s method of creating a random realm name, it was still possible to get back into the protected area using the back button in Firefox, so that didn’t work. Here’s my solution:
Since browsers attach the credentials to specific URLs, use virtual paths where a component of the path is actually a PHP script, and everything following it is part of the URI, such as:
By choosing a different number for the last component of the URL, browsers can be tricked into thinking that they are dealing with a completely different website, and thus prompting the user for credentials again.
Note that using a random, unrestricted number will still allow the user to hit the back button to get back into the page. You should keep track of this number in a server-side file or database and regenerate it upon each successful login, so that the last number(s) become invalid. Using an invalid number might result in a 403 response or, depending on how you feel that day, a 302 to a nasty website.
Care should be taken when linking from the page generated in this case, since relative links will be relative to the virtual and non-existant directory rather than the true script directory.
Then you need small piece of php code to parse this line and then everything will work like with mod_php:
A simpler approach on the post of:
bernard dot paques at bigfoot dot com
24-Sep-2004 01:42
This is another «patch» to the PHP_AUTH_USER and PHP_AUTH_PW server variables problem running PHP as a CGI.
It’s a variation of the script by Bernard Paques.
Thanks to him for that snippet.
To force a logout with Basic Auth, you can change the Realm out from under them to a different Realm.
This forces a new set of credentials for a new «Realm» on your server.
You just need to track the Realm name with the user/pass and change it around to something new/random as they log in and out.
I believe that this is the only 100% guaranteed way to get a logout in HTTP Basic Auth, and if it were part of the docs a whole lot of BAD user-contributed comments here could be deleted.
I used Louis example (03-Jun-2006) and it works well for me (thanks).
However, I added some lines, to make sure, the user does only get the Authentification-Window a few times:
// In the beginning, when the realm ist defined:
$_SESSION [ ‘CountTrials’ ] = 1 ;
?>
And then when it comes to check the authentification (ZEND-Tutorial):
You are authorized!
‘ ;
>
?>
noentry.php is slightely different from comeagain.php.
Back to the autherisation in CGI mode. this is the full working example:
# In the beginning the script checking the authorization place the code:
if ( count($userpass) == 2 ) <
#this part work not for all.
#print_r($userpass);die; #
For PHP with CGI, make sure you put the rewrite rule above any other rewrite rule you might have.
My symptom was that the REMOTE_USER (or REDIRECT_REMOTE_USER in my case) was not being set at all.
The cause: I had some other RewriteRule that was kickin in and was set as LAST rule.
I hope this helps.
= ‘test_login’ ;
$pass = ‘test_pass’ ;
Simpler WorkAround for missing Authorization header under CGI/FastCGI available in Apache HTTP Server 2.4.13 and later
Please don’t enable Authorization header with Basic Authentication, is very insecure.
To anybody who tried the digest example above and didn’t get it to work.
For me the problem seemed to be the deprecated use of ‘\’ (backslash) in the regex instead of the ‘$’ (Dollar) to indicate a backreference. Also the results have to be trimmed off the remaining double and single quotes.
Here’s the working example:
// function to parse the http auth header
function http_digest_parse($txt)
<
// protect against missing data
$needed_parts = array(‘nonce’=>1, ‘nc’=>1, ‘cnonce’=>1, ‘qop’=>1, ‘username’=>1, ‘uri’=>1, ‘response’=>1);
$data = array();
Probably there’s a more sophisticated way to trim the quotes within the regex, but I couldn’t be bothered 🙂
I spent the better part of a day getting this to work right. I had a very hard time thinking through what the browser does when it encounters an authentication request: seems to me that it tries to get the password, then reloads the page. so the HTML doesn’t get run. At least, this was the case with IE, I haven’t tested it with anything else.
// «standard» authentication code here, from the ZEND tutorial above.
Безопасный метод авторизации на PHP
Примечание: мини-статья написана для новичков
Давайте посмотрим вокруг: форумы, интернет магазины, гостевые книги и т.д. используют регистрацию и последующую авторизацию пользователей. Можно даже сказать, что это почти необходимая функция каждого сайта (только если это не домашняя страничка Васи Пупкина или не визитная карточка, какой-нибудь небольшой компании). Сегодня я хочу поделиться со всеми новичками информацией, о том, как лучше это все реализовать.
1. Модель (клиент)
Регистрация
— логин (a-z0-9)
— пароль
Вход
— логин
— пароль
Cookie
— уникальный идентификатор юзера
— хэш
Модель (сервер)
MySQL
Таблица users
user_id (int(11))
user_login (Varchar(30))
user_password (varchar(32))
user_hash (varchar(32))
user_ip (int(10)) по умолчанию 0
При регистрации в базу данных записываеться логин пользователя и пароль(в двойном md5 шифровании)
При авторизация, сравниваеться логин и пароль, если они верны, то генерируеться случайная строка, которая хешируеться и добавляеться в БД в строку user_hash. Также записываеться IP адрес пользователя(но это у нас будет опциональным, так как кто-то сидит через Proxy, а у кого-то IP динамический… тут уже пользователь сам будет выбирать безопасность или удобство). В куки пользователя мы записываем его уникальный индетификатор и сгенерированный hash.
Почему надо хранить в куках хеш случайно сгенерированной строки, а не хеш пароля?
1. Из-за невнимательности программиста, во всей системе могут быть дырки, воспользовавшийсь этими дырками, злоумышленик может вытащить хеш пароля из БД и подставить его в свои куки, тем самым получить доступ к закрытым данным. В нашем же случае, двойной хеш пароля не чем не сможет помочь хакеру, так как расшифровать он его не сможет(теоретически это возможно, но на это он потратит не один месяц, а может быть и год) а воспользоваться этим хешем ему негде, ведь у нас при авторизации свой уникальный хеш прикрепленный к IP пользователя.
2. Если злоумышленик вытащит трояном у пользователя уникальный хеш, воспользовать им он также не сможет(разве если только, пользователь решил принебречь своей безопастностью и выключил привязку к IP при авторизации).
2. Практика
—
— Структура таблицы `users`
CREATE TABLE `users` (
`user_id` int(11) unsigned NOT NULL auto_increment,
`user_login` varchar(30) NOT NULL,
`user_password` varchar(32) NOT NULL,
`user_hash` varchar(32) NOT NULL,
`user_ip` int(10) unsigned NOT NULL default ‘0’,
PRIMARY KEY (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=1 ;
register.php
// Страница регситрации нового пользователя
$err [] = «Логин может состоять только из букв английского алфавита и цифр» ;
$err [] = «Логин должен быть не меньше 3-х символов и не больше 30» ;
# проверяем, не сущестует ли пользователя с таким именем
$err [] = «Пользователь с таким логином уже существует в базе данных» ;
# Если нет ошибок, то добавляем в БД нового пользователя
# Убераем лишние пробелы и делаем двойное шифрование
header ( «Location: login.php» ); exit();
print «При регистрации произошли следующие ошибки:
» ;
login.php
// Страница авторизации
# Функция для генерации случайной строки
$chars = «abcdefghijklmnopqrstuvwxyzABCDEFGHI JKLMNOPRQSTUVWXYZ0123456789» ;
# Вытаскиваем из БД запись, у которой логин равняеться введенному
# Генерируем случайное число и шифруем его
$hash = md5 ( generateCode ( 10 ));
# Если пользователя выбрал привязку к IP
# Переводим IP в строку
# Записываем в БД новый хеш авторизации и IP
# Переадресовываем браузер на страницу проверки нашего скрипта
header ( «Location: check.php» ); exit();
print «Вы ввели неправильный логин/пароль» ;
check.php
// Скрипт проверки
print «Хм, что-то не получилось» ;
print «Включите куки» ;
Для защиты формы логина от перебора, можно использовать captcha.ru target=»_blank»>капчу.
Хочу отметить, что здесь я рассматривал авторизацию основоную на cookies, не стоит в комментариях кричать, что сессии лучше/удобнее и т.д. Спасибо.
Аутентификация и авторизация в микросервисных приложениях
Автор: Вячеслав Михайлов, Solutions Architect
Это вводная часть материала, основанного на докладе, прочитанном мной прошлым летом. Печатный материал предполагает больше информации, т.к. в одном докладе обычно не получается рассказать обо всех деталях.
Что такое аутентификация?
На процессах аутентификации и авторизации основано разделения прав доступа, без которого не обходится ни одно более или менее серьезное приложение. Поэтому понимать, как они происходили раньше и происходят теперь, очень важно, но, прежде чем углубиться в описание технологии, давайте разберемся с ключевыми терминами.
Идентификация — процесс определения, что за человек перед нами. Аутентификация — процесс подтверждения, что этот человек именно тот, за кого себя выдает. Авторизация — процесс принятия решения о том, что именно этой аутентифицированной персоне разрешается делать. То есть, это три разных, последовательных и взаимно не заменяемых понятия. Идентификацию часто подразумевают в составе аутентификации. Самое главное — четко различать аутентификацию и авторизацию.
В ходе аутентификации мы удостоверяемся, что человек, который к нам пришел, обладает доказательствами, подтверждающими личность. В этой статье речь в основном пойдет как раз об аутентификации.
Способы аутентификации
При использовании HTTP-протокола простейший способ аутентификации — Basic access authentication. В принципе этот протокол устарел и уже редко используется в интернете, особенно в незащищенных соединениях, но еще сохраняется во внутрикорпоративных системах, просто потому что некоторые из них созданы достаточно давно. Стоит разобраться, как он работает.
HTTP Basic Authentication
Первым, что при обращении к защищенному ресурсу сервер выдаст пользователю, не имеющему доступа, будет ошибка 401 Unauthorized. При этом ответ также содержит информацию о типе аутентификации (в нашем случае – Basic), который он может принимать, и контекст, в рамках которого эта аутентификация действует (Realm). Пользователь вводит логин и пароль, они упаковываются в Base64 и отправляются на сервер для проверки. Здесь существуют различные опасности. Самая распространенная — угроза man-in-the-middle attack, или атаки посредника, в ходе которой при использовании незащищенного соединения учетные данные могут перехватить злоумышленники в момент передачи от клиента к серверу или обратно.
HTTP Digest Authentication
Следующим этапом развития технологии стала чуть более сложная система HTTP digest authentication, которая исключает передачу учетных данных в открытом виде — здесь для проверки используется MD5-хеш с некоторыми примесями, что позволяет избежать подбора логина и пароля. Конечно, этот алгоритм выглядит более надежным, но и он подвержен целому ряду не самых сложных атак. Например, вот тут можно почитать об атаках более подробно.
Forms Authentication
Позднее появился процесс Forms authentication, при котором аутентификация происходит на более высоком уровне модели абстракции. HTTP-сервер при этом не сообщает об ошибке доступа, а просто перенаправляет неаутентифицированного пользователя на другую страницу. Обычно на этой странице отображаются поля для ввода логина и пароля, после заполнения которых формируется POST-запрос с данными и через защищенный канал направляется на сервер. Серверная сторона в свою очередь возвращает пользователю токен или идентификатор сессии, который сохраняется в Cookies и в дальнейшем используется для доступа к защищенному ресурсу.
Token Authentication
На схеме хорошо видно, как и в какой последовательности приложения обмениваются информацией при использовании аутентификацией по токенам.
На следующей схеме дополнительно отражены те этапы взаимодействия, в которых пользователь принимает непосредственное участие. Этот момент и является недостатком подобной схемы — нам всегда нужен пользователь, чтобы получить доступ к ресурсу.
OAuth2 & Open ID Connect
Дальнейшее усовершенствование процесса понадобилось ввиду того, что токен-аутентификация требует присутствия пользователя в момент получения доступа к защищенному ресурсу. Потому что Identity provider при передаче ему управления будет с пользователем взаимодействовать, запрашивая, например, логин и пароль.
В случае сервиса, который от имени пользователя должен через определенные промежутки времени опрашивать некий третий ресурс, — допустим, получать доступ к списку контактов в социальной сети — токен-аутентификация работать уже не будет. Дело в том, что идентификаторы сессии обычно живут очень недолго, чтобы в случае их перехвата злоумышленники получили доступ к сервису лишь на ограниченное время. Но из-за короткого срока действия токена не хватает, например, на ночной процесс.
В 2006 году в ходе работы над реализацией протокола Open ID для Twitter обнаружилась потребность в новом открытом протоколе авторизации. В 2007 инженеры Google и AOL начали совместную работу над ним, а в 2009 Twitter предложил своим пользователям решение, делегировавшее сторонним сервисам доступ к аккаунтам и основанное на протоколе OAuth. Три года спустя была опубликована новая версия — OAuth 2, упростившая разработку клиентских приложений и получившая целый ряд новых возможностей, среди которых оказалось и обновление токена без участия пользователя. Многие сервисы начали использовать этот протокол еще до его официального утверждения.
Разбираемся детально ху из ху
OpenID 1.0 (2006) & OpenID 2.0 (2007) позволяли приложению(арб) запрашивать у доверенного сервера (authority) проверку пользователя(user). Отличия между версиями для нас несущественны.
Взгляд сверху
Обычно в системах встречаются разные компоненты: пользователи, работающие через браузер, пользователи, взаимодействующие с сервером через мобильные приложения, и просто серверные приложения, нуждающиеся в принадлежащих вам данных, хранящихся на других серверах, доступ к которым осуществляется через Web API.
Single sign-on — технология единого входа — позволяет пользователю переключаться между различными приложениями без повторной аутентификации. Используя SSO можно избежать множественных логинов, так что пользователь просто не будет замечать этих переключений. При этом ситуации, когда в рамках вашей инфраструктуры таких приложений будет больше одного, встречаются постоянно. Технология единого входа особенно удобна в больших энтерпрайз-системах, состоящих из десятков приложений, слабо связанных между собой. Вряд ли пользователи будут довольны, вводя логин и пароль при каждом обращении к системе учета рабочего времени, корпоративному форуму или внутренней базе документов.
В качестве реализации мы рассматриваем протокол OAuth2. В принципе, существуют и другие, например, Kerberos, успешно взаимодействующий с Windows, но в случае гетерогенной сети, в которой существуют компьютеры, использующие и Windows-, и Mac-, и UNIX-системы, использовать проприетарные протоколы зачастую неудобно. Тем более, это касается случаев, когда доступ к вашим сервисам осуществляется через веб — здесь OAuth2 оказывается лучшим кандидатом.
На рисунке выше показано, какие именно протоколы используются при каждом типе взаимодействия.
Как мы знаем из раздела «разбираемся детально ху из ху», OpenID Сonnect нужен, чтобы получить у пользователя его учетные данные и проверить их. OAuth 2.0 нужен, чтобы получать токены доступа и с ними обращаться к ресурсам.
Терминология OAuth2 & OpenID Connect
Сервис выдачи токенов
Open ID Connect Provider — важнейший объект всей конструкции централизованного сервиса аутентификации, он также может называться Security Token Service, Identity Provider authorization server и т. д. Различные источники называют его по-разному, но по смыслу это сервис, который выдает токены клиентам.
Клиент
Client — устройство или программа (браузер, приложение), которым требуется либо токен для аутентификации пользователя, либо токен для доступа к какому-то ресурсу (подразумевается, что данный ресурс «знаком» с тем конкретным «Security Token Service» у которого клиент запрашивает токен для доступа).
Пользователь
User — собственно конечный пользователь — человек.
Область (scope)
Scope — идентификатор ресурса, к которому клиент хочет получить доступ. Список scope посылается в адрес сервиса выдачи токенов в составе запроса на аутентификацию.
По умолчанию все клиенты имеют возможность запрашивать любые области, но это можно (и нужно) ограничивать в конфигурации сервиса выдачи токенов.
Scopes бывают двух видов:
Запрос на аутентификацию
Authentication/Token Request — процесс запроса аутентификации.
Токен личности
Identity Token — подтверждение аутентификации. Этот токен содержит минимальный набор информации о пользователе.
Токен доступа
Access Token — информация, что конкретному пользователю разрешается делать. Клиент запрашивает Access Token и затем использует его для доступа к ресурсам (Web APIs). Access Token содержит информацию о клиенте и пользователе, если она присутствует. Важно понимать, что есть такие типы авторизации, при которых пользователь в процессе непосредственно не участвует (подробнее об этом в следующей части)
Токен обновления
Refresh Token — токен, по которому STS вернет новый Access Token. В зависимости от режима работы, Refresh Token может быть многоразовым и одноразовым. В случае с одноразовым токеном, при запросе нового Access Token будет также сформирован готовый Refresh Token, который следует использовать при повторном обновлении. Очевидно, что одноразовые токены более безопасны.
Более подробно о составе токенов в разделе «структура токена».
Процесс аутентификации
При обращении пользователя к клиенту, тот перенаправляет пользователя на Open ID Connect Provider, который запрашивает у пользователя логин и пароль. В случае успешного прохождения проверки параметров аутентификации он возвращает назад identity token и access token, с которыми пользователь может обращаться к защищенному ресурсу.
Структура токена
Формат
В реализации OAuth2 используется так называемый jwt-токен, который состоит из трех частей. Допустим, при обращении к Identity provider вы отправляете логин/пароль и в ответ получаете токен. Он будет включать в себя: Header (заголовок), Payload (контент) и Signature (подпись). На сайте jwt.io его можно декодировать и посмотреть содержимое формате JSON. На этом сайте вы также найдете описание правил формирования jwt-токенов.
В том, что токены в процессе обмена передаются незашифрованными, ничего страшного нет. Мы изначально исходим из предположения, что коммуникация происходит по защищенному HTTPS-каналу, и повторное шифрование токена было бы избыточным. Единственное, в чем нам нужно убедиться – то, что токен не был подменен или сфальсифицирован на клиентской стороне, для этого достаточно иметь подпись и проверять ее на сервере. Кроме того, токен не содержит никакой критически важной информации.
Кроме identity tokens, есть еще и аccess tokens, которые содержат информацию о выданных пользователю клеймах. Срок действия access token достаточно короткий, потому что его хищение может обеспечить несанкционированный доступ к ресурсу. Т. е. злоумышленник, если ему удастся заполучить токен этого типа, доступ получит на очень непродолжительное время. Для получения нового access token используется refresh token, который обычно не фигурирует в незащищенных средах, в частности в режиме доступа из браузера он вообще не используется. Какие именно токены будут возвращены клиенту в процессе аутентификации, разберемся в следующей части.
Основные поля
Кратко остановимся на том, какие есть стандартные полях в токене и зачем они нужны:
Заключение первой части
В этой статье мы постарались дать теоретический и терминологический фундамент, который понадобится нам создании работающего решения в следующих статьях.
Минимальная реализация интеграция Identity Server в ваше приложение выглядит так:
Минимальная реализация интеграции веб-клиента с Identity Server:
Минимальная реализация интеграции веб-API с Identity Server: