Современные стандарты идентификации: oauth 2.0, openid connect, webauthn
Содержание:
Создание API для входа пользователей
В приведенном ниже коде установим заголовки, чтобы файл знал откуда должен поступить запрос и какой тип данных принимается
Откроем файл api/login.php и поместим в него следующий код
Мы сравним электронную почту пользователя и пароль из базы данных, поэтому нам нужно подключение к БД.
Нам также нужно создать экземпляр пользовательской таблицы, это позволит нам проверить, существует ли электронная почта, и прочитать хешированный пароль.
Замените комментарий // здесь будет соединение с БД в файле login.php следующим кодом:
Создание файла конфигурации (ядра)
Файл login.php не будет работать без файла core.php. Этот файл содержит общие настройки / переменные нашего приложения.
У нас есть переменные, используемые нашей библиотекой JWT для кодирования и декодирования токена. Значение $key должно быть вашим собственным и уникальным секретным ключом.
iss — адрес или имя удостоверяющего центра
aud — имя клиента для которого токен выпущен
iat — время, когда был выпущен JWT
nbf — время, начиная с которого может быть использован (не раньше, чем)
Вы также можете использовать exp — идентифицирует время истечения срока действия токена
Откроем api/config/core.php и добавим следующий код
Скачайте библиотеку PHP-JWT c GitHub’а
Скопируйте содержимое библиотеки в api/libs/
Тест входа в систему
Введём следующий URL запрос
В Body вставьте следующее значение JSON
Нам нужно сохранить сгенерированный JWT чтобы потом его использовать для проверки
Для проверки на неудачный вход в систему измените значение пароля на 222 (это неверный пароль)
Usage
Models
Auth has two models, model is used to save login information, model is used to save user information.
The reason we save auth and user info into two different models, as we want to be able to link a user to mutliple auth info records, so a user could have multiple ways to login.
If this is not required for you, you could just set those two models to same one or skip set .
AuthIdentityModel
Different provider usually use different information to login, like provider use username/password, use github user ID, so for each provider, it will save those information into its own record.
UserModel
By default, there is no defined, even though, you still be able to use features, will return used auth info record as logged user.
But usually your application will have a model, after you set its value, when you register a new account from any provider, Auth will create/get a user with , and link its ID to the auth identity record.
Customize views
Auth using Render to render pages, you could refer it for how to register func maps, extend views paths, also be sure to refer BindataFS if you want to compile your application into a binary.
If you want to preprend view paths, you could add them to , which would be helpful if you want to overwrite the default (ugly) login/register pages or develop auth themes like https://github.com/qor/auth_themes
Session Storer
By default, Auth is using session’s default manager to save data into cookies, but in order to save cookies correctly, you have to register session’s Middleware into your router, e.g:
func main() {
mux := http.NewServeMux()
// Register Router
mux.Handle("/auth/", Auth.NewServeMux())
http.ListenAndServe(":9000", manager.SessionManager.Middleware(mux))
}
Redirector
After some Auth actions, like logged, registered or confirmed, Auth will redirect user to some URL, you could configure which page to redirect with , by default, will redirct to home page.
If you want to redirect to last visited page, redirect_back is for you, you could configure it and use it as the Redirector, like:
var RedirectBack = redirect_back.New(&redirect_back.Config{
SessionManager: manager.SessionManager,
IgnoredPrefixes: []string{"/auth"},
}
var Auth = auth.New(&auth.Config{
...
Redirector: auth.Redirector{RedirectBack},
})
BTW, to make it works correctly, need to save last visisted URL into session with session manager for each request, that’s means, you need to mount , and ‘s middleware into router.
http.ListenAndServe(":9000", manager.SessionManager.Middleware(RedirectBack.Middleware(mux)))
Аутентификация в соцсетях
Уверен, эта картинка знакома всем:
Это часто называют аутентификацией в соцсетях (Social sign-in) или социальным логином (Social Login). Вы можете аутентифицировать пользователей по их аккаунтам в соцсетях. Тогда пользователям не придётся регистрироваться отдельно в вашем приложении.
Формально социальный логин — это не отдельный метод аутентификации. Это разновидность единой точки входа с упрощением процесса регистрации/входа пользователя в ваше приложение.
Лучшее из двух миров
Пользователи могут войти в ваше приложение одним кликом, если у них есть аккаунт в одной из соцсетей. Им не нужно помнить логины и пароли. Это сильно улучшает опыт использования вашего приложения. Вам как разработчику не нужно волноваться о безопасности пользовательских данных и думать о проверке адресов почты — они уже проверены соцсетями. Кроме того, в соцсетях уже есть механизмы восстановления пароля.
Как использовать
Как разработчик вы должны разбираться в работе этого метода аутентификации. Большинство соцсетей в качестве механизма аутентификации используют авторизацию через OAuth2 (некоторые используют OAuth1, например Twitter). Разберёмся, что такое OAuth. Соцсеть — это сервер ресурсов, ваше приложение — клиент, а пытающийся войти в ваше приложение пользователь — владелец ресурса. Ресурсом называется пользовательский профиль / информация для аутентификации. Когда пользователь хочет войти в ваше приложение, оно перенаправляет пользователя в соцсеть для аутентификации (обычно это всплывающее окно с URL’ом соцсети). После успешной аутентификации пользователь должен дать вашему приложению разрешение на доступ к своему профилю из соцсети. Затем соцсеть возвращает пользователя обратно в ваше приложение, но уже с токеном доступа. В следующий раз приложение возьмёт этот токен и запросит у соцсети информацию из пользовательского профиля. Так работает OAuth (ради простоты я опустил технические подробности).
Для реализации такого механизма вам может понадобиться зарегистрировать своё приложение в разных соцсетях. Вам дадут app_id и другие ключи для конфигурирования подключения к соцсетям. Также есть несколько популярных библиотек/пакетов (вроде Passport, Laravel Socialite и т. д.), которые помогут упростить процедуру и избавят от излишней возни.
Разбираемся детально ху из ху
- OpenID — для проверки учетных данных пользователя (identification & authentication).
- OAuth — про то, чтобы получать доступ к чему-то.
- OpenID Connect — и про и то, и про другое одновременно.
OpenID 1.0OpenID 2.0
- User –> App: Привет, это Миша.
- App –> Authority: Вот «это» Миша?
- Authority и User общаются тет-а-тет.
- Authority –> App: Да, это Миша.
OpenID Attribute Exchange 1.0
- User –> App: Привет, это Миша.
- App –> Authority: Вот «это» Миша? И если это Миша, то пришлите мне его email.
- Authority и User общаются тет-а-тет.
- Authority –> App: Да, это Миша. И его email xxx@xxx.xxx.
OAuth 1.0
- App –> User: Mы бы хотели получить ваши картинки с другого сервера.
- Authority и User общаются тет-а-тет.
- Authority –> App: Вот вам билет (access token) на 15 минут.
- App –> Third-party server: Нам тут по билету можно получить фотографии для этого пользователя.
OAuth 2.0OpenID Connect
- Проверять учетные данные пользователя.
- Получать профиль пользователя (или его части).
Взгляд сверху
Как мы знаем из раздела «», 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
Проблема входа в систему
То, что происходит после того, как OAuth 2.0 установил способ доступа к сторонним API, заключается в том, что приложение также требуется регистрировать пользователей у себя. Используя наш пример: HireMe123 нужно, чтобы пользователь MyCalApp мог залогиниться, используя свою учетную запись MyCalApp, даже несмотря на то, что он не был зарегистрирован в HireMe123.
Но, как мы упоминали выше, OAuth 2.0 предназначен только для делегированного доступа. Это не протокол аутентификации. Но это не помешало людям попытаться использовать его и для аутентификации, и это представляет проблему.
Проблемы с использованием токенов доступа для аутентификации
Если HireMe123 предполагает успешный вызов API MyCalApp с токеном доступа, достаточным что бы пользователь считался аутентифицированным, у нас возникают проблемы, поскольку у нас нет способа проверить, был ли выдан токен доступа правильному пользователю.
Например:
- Кто-то мог украсть токен доступа у другого пользователя
- Маркер доступа мог быть получен от другого клиента (не HireMe123) и введен в HireMe123
Это называется запутанной проблемой делегирования. HireMe123 не знает, откуда взялся этот токен и кому он был выдан. Если мы помним: аутентификация — это проверка того, что пользователь — это тот, кем он себя заявляет. HireMe123 не может знать это из-за того, что он может использовать этот токен доступа для доступа к API.
Как уже упоминалось, это не остановило людей от неправильного использования токенов доступа и OAuth 2.0 для аутентификации. Быстро стало очевидно, что формализация аутентификации поверх OAuth 2.0 была необходима, чтобы разрешить входы в приложения сторонних разработчиков, сохраняя безопасность приложений и их пользователей.
Создаём регистрацию на PHP:
Для этого пишем скрипт который будет ниже:
PHP
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
// Проверяем нажата ли кнопка отправки формы if(isset($_REQUEST’doGo’)){ // Все последующие проверки, проверяют форму и выводят ошибку // Проверка на совпадение паролей if($_REQUEST’pass’!==$_REQUEST’pass_rep’){ $error=’Пароль не совпадает’; } // Проверка есть ли вообще повторный пароль if(!$_REQUEST’pass_rep’){ $error=’Введите повторный пароль’; } // Проверка есть ли пароль if(!$_REQUEST’pass’){ $error=’Введите пароль’; } // Проверка есть ли email if(!$_REQUEST’email’){ $error=’Введите email’; } // Проверка есть ли логин if(!$_REQUEST’login’){ $error=’Введите login’; } // Если ошибок нет, то происходит регистрация if(!$error){ $login=$_REQUEST’login’; $email=$_REQUEST’email’; // Пароль хешируется $pass=password_hash($_REQUEST’pass’,PASSWORD_DEFAULT); // Если день рождения не был указан, то будет самый последний год из доступных $DOB=$_REQUEST’year_of_birth’; // Добавление пользователя mysqli_query($db,»INSERT INTO `users` (`login`, `email`, `password`, `DOB`) VALUES (‘».$login.»‘,'».$email.»‘,'».$pass.»‘, ‘».$DOB.»‘)»); // Подтверждение что всё хорошо echo’Регистрация прошла успешна’; }else{ // Если ошибка есть, то выводить её echo$error; } } ?> <!DOCTYPE html> <html lang=»ru»> <head> <meta charset=»UTF-8″> <meta name=»viewport»content=»width=device-width, initial-scale=1.0″> <meta http-equiv=»X-UA-Compatible»content=»ie=edge»> <title>Зарегистрироваться<title> <head> <body> <form action=»<?= $_SERVER ?>»> <p>Логин<input type=»text»name=»login»id=»»><samp style=»color:red»>*<samp><p> <p>EMail<input type=»email»name=»email»id=»»><samp style=»color:red»>*<samp><p> <p>Пароль<input type=»password»name=»pass»id=»»><samp style=»color:red»>*<samp><p> <p>Повторитепароль<input type=»password»name=»pass_rep»id=»»><samp style=»color:red»>*<samp><p> <?php$year=date(‘Y’);?> Годрождения <select name=»year_of_birth»id=»»> <option value=»»>—-<option> <?phpfor($i=$year-14;$i>$year-14-100;$i—){?> <option value=»<?= $i ?>»><?=$i?><option> <?php}?> <select> <p><input type=»submit»value=»Зарегистрироваться»name=»doGo»><p> <form> <body> <html> |
HTML я не стал рассказывать, так как, там всё понятно, да и вообще программист должен разберется в коде.
Usage
Simple:
See below for instructions on how to setup your .
docker-compose.yml:
version: '3'
services:
traefik:
image: traefik:v2.2
command: --providers.docker
ports:
- "8085:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
traefik-forward-auth:
image: thomseddon/traefik-forward-auth:2
environment:
- PROVIDERS_GOOGLE_CLIENT_ID=your-client-id
- PROVIDERS_GOOGLE_CLIENT_SECRET=your-client-secret
- SECRET=something-random
- INSECURE_COOKIE=true # Example assumes no https, do not use in production
labels:
- "traefik.http.middlewares.traefik-forward-auth.forwardauth.address=http://traefik-forward-auth:4181"
- "traefik.http.middlewares.traefik-forward-auth.forwardauth.authResponseHeaders=X-Forwarded-User"
- "traefik.http.services.traefik-forward-auth.loadbalancer.server.port=4181"
whoami:
image: containous/whoami
labels:
- "traefik.http.routers.whoami.rule=Host(`whoami.mycompany.com`)"
- "traefik.http.routers.whoami.middlewares=traefik-forward-auth"
Advanced:
Please see the examples directory for a more complete docker-compose.yml or kubernetes/simple-separate-pod.
Also in the examples directory is docker-compose-auth-host.yml and kubernetes/advanced-separate-pod which shows how to configure a central auth host, along with some other options.
Provider Setup
Below are some general notes on provider setup, specific instructions and examples for a number of providers can be found on the Provider Setup wiki page.
Create a new project then search for and select «Credentials» in the search bar. Fill out the «OAuth Consent Screen» tab.
You must set the and config options.
OpenID Connect
Any provider that supports OpenID Connect 1.0 can be configured via the OIDC config options below.
You must set the , and config options.
Please see the Provider Setup wiki page for examples.
Generic OAuth2
For providers that don’t support OpenID Connect, we also have the Generic OAuth2 provider where you can statically configure the OAuth2 and «user» endpoints.
You must set:
- — URL the client should be sent to authenticate the authenticate
- — URL the service should call to exchange an auth code for an access token
- — URL used to retrieve user info (service makes a GET request)
- — Client ID
- — Client Secret
You can also set:
- — Any scopes that should be included in the request (default: profile, email)
- — How token is presented when querying the User URL. Can be or , defaults to . With the token is provided in an Authorization header, with query the token is provided in the query string value.
Please see the Provider Setup wiki page for examples.
Подключение БД к PHP:
Для этого создаём файлы connect.php, index.php и checkin.php. Сначала мы в connect.php подключаемся к самой БД, для этого пишем код ниже.
PHP
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?php $server=’localhost’;// Имя или адрес сервера $user=’root’;// Имя пользователя БД $password=»;// Пароль пользователя $db=’authorization-system’;// Название БД $db=mysqli_connect($server,$user,$password,$db);// Подключение // Проверка на подключение if(!$db){ // Если проверку не прошло, то выводится надпись ошибки и заканчивается работа скрипта echo»Не удается подключиться к серверу базы данных!»; exit; } |
Подключаем connect.php к index.php
Default
|
1 2 |
// Подключение БД require_once’connect.php’; |
Проверяем скрипт, для этого запускаем программу.
После того как проверили на работа способность, можете убрать вывод надписи «подключение к базе данных прошло успешно».
Аутентификация на основе токенов
Аутентификация на основе токенов в последние годы стала очень популярна из-за распространения одностраничных приложений, веб-API и интернета вещей. Чаще всего в качестве токенов используются Json Web Tokens (JWT). Хотя реализации бывают разные, но токены JWT превратились в стандарт де-факто.
При аутентификации на основе токенов состояния не отслеживаются. Мы не будем хранить информацию о пользователе на сервере или в сессии и даже не будем хранить JWT, использованные для клиентов.
Процедура аутентификации на основе токенов:
- Пользователь вводит имя и пароль.
- Сервер проверяет их и возвращает токен (JWT), который может содержать метаданные вроде user_id, разрешений и т. д.
- Токен хранится на клиентской стороне, чаще всего в локальном хранилище, но может лежать и в хранилище сессий или кук.
- Последующие запросы к серверу обычно содержат этот токен в качестве дополнительного заголовка авторизации в виде Bearer {JWT}. Ещё токен может пересылаться в теле POST-запроса и даже как параметр запроса.
- Сервер расшифровывает JWT, если токен верный, сервер обрабатывает запрос.
- Когда пользователь выходит из системы, токен на клиентской стороне уничтожается, с сервером взаимодействовать не нужно.
У метода есть ряд преимуществ:
- Главное преимущество: поскольку метод никак не оперирует состояниями, серверу не нужно хранить записи с пользовательскими токенами или сессиями. Каждый токен самодостаточен, содержит все необходимые для проверки данные, а также передаёт затребованную пользовательскую информацию. Поэтому токены не усложняют масштабирование.
- В куках вы просто храните ID пользовательских сессий, а JWT позволяет хранить метаданные любого типа, если это корректный JSON.
- При использовании кук бэкенд должен выполнять поиск по традиционной SQL-базе или NoSQL-альтернативе, и обмен данными наверняка длится дольше, чем расшифровка токена. Кроме того, раз вы можете хранить внутри JWT дополнительные данные вроде пользовательских разрешений, то можете сэкономить и дополнительные обращения поисковые запросы на получение и обработку данных.
Допустим, у вас есть API-ресурс /api/orders, который возвращает последние созданные приложением заказы, но просматривать их могут только пользователи категории админов. Если вы используете куки, то, сделав запрос, вы генерируете одно обращение к базе данных для проверки сессии, ещё одно обращение — для получения пользовательских данных и проверки, относится ли пользователь к админам, и третье обращение — для получения данных.
А если вы применяете JWT, то можете хранить пользовательскую категорию уже в токене. Когда сервер запросит его и расшифрует, вы можете сделать одно обращение к базе данных, чтобы получить нужные заказы. - У использования кук на мобильных платформах есть много ограничений и особенностей. А токены сильно проще реализовать на iOS и Android. К тому же токены проще реализовать для приложений и сервисов интернета вещей, в которых не предусмотрено хранение кук.
Благодаря всему этому аутентификация на основе токенов сегодня набирает популярность.
Automatic Management of the Authorization HTTP Header
Both Spring 3.0 and 3.1 and now 4.x have very good support for the Apache HTTP libraries:
- Spring 3.0, the CommonsClientHttpRequestFactory integrated with the now end-of-life’d HttpClient 3.x
- Spring 4.0 introduced async support via the HttpComponentsAsyncClientHttpRequestFactory
Let’s start setting things up with HttpClient 4 and Spring 4.
And with that, everything is in place – the RestTemplate will now be able to support the Basic Authentication scheme just by adding a BasicAuthorizationInterceptor;
And the request:
For an in-depth discussion on how to secure the REST Service itself, check out this article.
Пути решения
MACDAC(ACL)RBACАВАСPBAC, RAdAC, CBACшикарный обзор от CUSTIS
| Требование от бизнеса | Решение | |
|---|---|---|
| 1 | Пользователь, не имеющий отношения к конкретному договору, не должен его видеть в системе | Тут напрашивается ACL, поскольку определить отношение пользователя к бизнес-процессу достаточно сложно, не записывая его в какой-то список в момент вовлечения. Это будет оптимальным решением с точки зрения производительности чтения относительно реализации с помощью политик. |
| 2 | Автор договора должен видеть его на всех этапах | Требование может быть реализовано обоими механизмами, но оптимальным я считаю ACL, поскольку в этом случае будет проще реализовать требование №3 от ИБ. |
| 3 | Создавать договор имеет право пользователь с грейдом не ниже 10 | Это политика (PBAC), без вариантов |
| 4 | Визирующий должен видеть договор начиная с поступления к нему на этап и далее | ACL будет оптимален |
| 5 | Руководители подразделений должны видеть договоры своих подразделений вниз по иерархии | Замечательная задача для PBAC, но его применение может снизить производительность чтения, а требования 1 и 2 от ИБ потребуют дополнительных усилий, поэтому стоит подумать над реализацией. |
| 6 | Автор договора и руководитель подразделения имеют право отозвать договор на любом этапе согласования | PBAC справится отлично |
| 7 | Руководство и секретариат головного офиса должны видеть документы всех филиалов | PBAC, с теми же ограничениями что и в п. 5 |
| 8 | Пользователь, создавший договор, не должен иметь права его завизировать | Это требование можно было бы закрыть с помощью PBAC, однако так делать не стоит. Это то самое место, где авторизация вступает в конфликт с бизнес-логикой, и если происходит такая ситуация, ответственность стоит отдать бизнес-логике. |
| Требование от ИБ | Решение | |
|---|---|---|
| 1 | Знать, кто имеет доступ к конкретному договору | Общий журнал для ACL и PBAC |
| 2 | Знать, кто имел доступ к конкретному договору в заданный момент времени | Общий журнал для ACL и PBAC |
| 3 | Лишать пользователя доступа к ранее доступным документам при изменении его должностных обязанностей | ACL |
Установка
Требования к серверу
Фреймворк Laravel предъявляет некоторые системные требования. Конечно же, виртуальная машина Laravel Homestead соответствует всем этим требованиям, поэтому настоятельно рекомендуется использовать Homestead в качестве основной локальной среды разработки с Laravel.
Однако, если вы не используете Homestead, вам необходимо убедиться, что ваш сервер соответствует следующим требованиям:
- PHP >= 7.2.0
- Расширение PHP BCMath
- Расширение PHP Ctype
- Расширение PHP Fileinfo
- Расширение PHP JSON
- Расширение PHP Mbstring
- Расширение PHP OpenSSL
- Расширение PHP PDO
- Расширение PHP Mbstring
- Расширение PHP Tokenizer
- Расширение PHP XML
Установка Laravel
Laravel использует Composer для управления своими зависимостями, поэтому убедитесь в том, что Composer установлен на вашей машине.
С помощью установщика Laravel
Сначала скачайте установщик Laravel с помощью Composer:
Проверьте, чтобы директория composer’а находилась в переменной $PATH, что позволит вашей системе найти и выполнить команду . Эта директория располагается в разных местах в зависимости от вашей операционной системы, но обычно она находится тут:
- macOS:
- Windows:
- Linux: или
Также вы можете определить директорию выполнив команду (смотрите первую строчку вывода).
После установки команда создаёт свежую установку Laravel в указанной вами директории. Например, создаст директорию с названием , которая будет содержать свежую установку Laravel со всеми зависимостями:
Локальный сервер разработки
Если локально у вас уже установлен PHP и вы хотели бы использовать встроенный сервер для работы вашего приложения, то вы можете использовать команду Artisan . Эта команда запустит сервер разработки по адресу :
Конечно же, Homestead и Valet предоставляют наиболее надежные способы локальной разработки.
Настройка
Общедоступная директория
После установки Laravel вам следует указать директорию в качестве корневой директории вашего веб-сервера. Файл в этой категории выступает в роли фронт-контроллера всех HTTP-запросов, поступающих в ваше приложение.
Файлы настройки
Все файлы настройки фреймворка Laravel расположены в директории . Параметры в каждом из них снабжены комментариями, поэтому не стесняйтесь пройтись по этим файлам и познакомиться с доступными параметрами настройки.
Права доступа на директории
Так же, после установки Laravel вам может потребоваться настройка некоторых прав доступа. Директории внутри и должны быть доступны для записи веб-сервером, в противном случае Laravel не запустится. Если вы используете виртуальную машину Homestead, то эти права доступа уже установлены.
Ключ приложения
Следующее, что вы должны сделать после установки Laravel, это создать ключ шифрования для вашего приложения в виде случайного набора символов. Если вы установили Laravel через Composer или установщик Laravel, то этот ключ уже был создан с помощью команды .
Как правило, это строка должна быть длиной в 32 символа. Ключ должен быть указан в параметре файла окружения . Если вы не переименовывали файл в , то следует сделать это сейчас. Если ключ приложения не создан, то сессии ваших пользователей и другие шифруемые данные не будут в безопасности!
Дополнительная настройка
Laravel практически не требует настройки из коробки. Вы сразу можете начать разработку! Однако, рекомендуем ознакомиться с файлом — он содержит в себе несколько параметров, таких как часовой пояс () и локаль (), которые вы можете изменить согласно потребностям вашего приложения.
Вы также можете настроить некоторые дополнительные компоненты Laravel, такие как: