- Как информационная система работает с ЕСИА
- 5 Реализация микросервисов
- 3 Как использовать обобщенную модель данных
- 1 Закрытый онлайн аукцион
- 2 Логистика
- 3 Секретные части документа
- 4 Команда и ее проекты
- SPA (Single Page Application)
- Преимущества SPA
- Преимущества микросервисной архитектуры
- Аутентификация и авторизация в проекте с микросервисной архитектурой
- Вариант 1. Аутентификация на каждом микросервисе
- Проблемы этого решения
- Вариант 2. Работа с пользователями в отдельном микросервисе
- Вариант 3. Паттерн API Gateway
- Вариант 1. Авторизация на MS Auth
- Вариант 2. Авторизация на ресурсных микросервисах
- Межсервисная аутентификация
- Социальный вход
- 4 Проектируем микросервисы для работы чайников
- 2 Архитектура решения
- Биометрическая идентификация
- Истоки проблемы
- Архитектурные модели реализации АА
- 2 Обобщенная модель данных
- 1 Пользователь
- 2 Сервис
- 3 Ресурс
- 4 Разрешение
- 5 Роль
- 6 Группа
- 7 Вертикальное и горизонтальное разграничение доступа.
- 8 Глобальность/локальность авторизации доступа в микросервисах
- 10 О кешировании данных
- Архитектору безопасности на заметку
- Что представляет из себя база данных.
- Что же теперь делать
- Теория. Виды архитектуры
- Монолитная архитектура
Как информационная система работает с ЕСИА
ЕСИА является прослойкой между стандартным содержанием приложения и его защищёнными данными. Если пользователю не требуются услуги, которые требуют верификации личности, он может не проходить дополнительную авторизацию. Когда же он захочет попасть в этот раздел, приложение переадресует его на Портал госуслуг, а после успешной авторизации – вернёт обратно.
Технически процесс выглядит так:
1. Пользователь обращается к защищённому ресурсу информационной системы (например, при онлайн-покупке полиса ОСАГО).
2. Информационная система направляет в ЕСИА запрос на аутентификацию.
4. После успешной аутентификации ЕСИА передаёт в информационную систему пакет с идентификационными данными пользователя, информацию об уровне его учётной записи и контексте аутентификации.
5. На основании этой информации система открывает пользователю доступ.
5 Реализация микросервисов
Весь проект поделен на несколько репозиториев:
Как работать с проектами
В каждом проекте есть кофигурация docker-compose с минимальной для каждого сервиса конфигурацией, лучшим вариантом запуска будет sh start.sh. Остановить сервисы можно при помощи docker-compose down, если этого не сделать, то выполнить скрипт из папок других сервисов вы не сможете.
В скрипте инициализации БД ролевой модели выставлено немного пользователей — 10к всего лишь, рекомендую для тестов увеличить до 500к хотя бы. Инициализация займет примерно 100 секунд.
Как устроены test suites
Создаете конфигурацию запуска с мейн классом org.lastrix.perf.tester. PerfTester, в аргумент задаете имя класса test suite, через vm аргументы задаете параметры -Dperf.tester.warmup.round.time=PT1S -Dperf.tester.test.round.time=PT60S -Dperf.tester.test.threads.max=32 -Dperf.tester.test.threads.min=4 -Dperf.tester.test.round.count=1
Для начала разберемся с базой данных ролевой модели:
Для работы с таблицами нам потребуется сделать REST API, причем одно для пользователей — людей, второе для пользователей — сервисов.
Само апи довольно легко в понимании, но оно работает медленно (в районе 4к-7к рпс из-за БД), причем как получение ролей пользователя, так и проверка наличия ролей. Для ускорения работы необходимо сделать кеширование, поэтому добавляем в конфигурацию mafp.role.cache.enable. Кеш можно сделать в виде карты, но лучше использовать уже готовое решение com.google.common.cache. Cache и сэкономить себе кучу нервов, потому что через HashMap или WeakHashMap сделать быстро не удастся.
И в данный момент у нас появляется вопрос, а что именно нужно кешировать? В данном случае лучшим вариантом будет — сами роли, вернее их имена на каждого пользователя, так мы сэкономим запросы к БД.
В абстрактном классе заведем кеш под эти данные, но есть одно но. Если хранить Set, то нам придется столкнуться с тем, что поиск в случае большого количества ролей у пользователя будет работать медленно (в JVM строки никогда не работали быстро и не будут). Так же проблемой будет то, что строки, которые мы получим из хибернейта не будут интернированными или каким-то образом преобразованными до синглтонов в рамках нашего кеша, т.е. «a» == «a» всегда для нас будет ложно, и соответственно будет сравнение строк, а нужно — указателей или простых значений, например целых чисел. Это помимо того, что у нас память будет забиваться одними и теми же строками.
Поэтому необходимо добавить карту, в которой будем хранить меппинг (Строка, Целое). И в кеше хранить уже не набор имен ролей пользователя, а набор идентификаторов ролей пользователя, причем эти числа могут не совпадать с идентификаторами в вашей БД. Поиск Integer в HashSet выполняется намного быстрее, чем строки, при этом у вас де факто все строки будут интернированными, что в нашем случае является обязательным шагом — иначе потребление памяти будет расти неконтролируемым образом.
Получив абстрактный класс, можно реализовать его для самого ролевого сервиса, что бы авторизовать доступы к нему, а так же для клиента, что бы проще было пользоваться в других сервисах. Обратите внимание, что на клиенте мы кешируем не все роли, а только те, что зарегистрированы в белом списке, это позволит нам на каждом сервисе при желании хранить хоть 100к строк кеша, потратив чуть больше 10 мб хипа.
Если инициализировать БД 500к пользователями, 10к ролей и каждому пользователю выдать до 10 ролей, то можно провести нагрузочное тестирование. Результат на выданных 4 ядрах от моего i7-9700k получится скоромный — среднее 12992, минимум 12832, максимум 13088 rps. Результат получен на 16 потоках клиента.
Но основная проблема при тестировании вашей авторизации — это тот факт, что авторизовать надо работу чужого сервиса, вы можете рисовать любые цифры, но другие сервисы не будут работать с приемлемой производительностью.
Идеальным тестом для авторизации — является отношение количества пустых запросов за единицу времени к количеству авторизованных пустых запросов за единицу времени для N (желаемое число под в вашей системе, требующих авторизацию, хотя вы можете вычислять это значение от 1 до N и показывать в виде графика). При этом записывать будем в виде Ка1 коэффициент авторизации 1, если количество под равно 1. Чем ближе к 1 это значение, тем лучше работает ваша авторизация как слой. Именно поэтому полученные выше 13к рпс не имеют никакого значения, даже если вы сделаете авторизацию, которая выдает 10e100 rps, она будет бесполезна, если коэффициент авторизации окажется скажем 1000, потому что плохим результатом является уже 100 — т.е. ваша авторизация в 100 раз замедляет ничего не делающее приложение.
В данной статье будет измеряться только Ка1, потому что железа нет.
И напоследок попьем чай (делаем инсерты в БД) в 6 потоков клиента на POST /api/v1/tea получим среднее 1086, минимум 1086, максимум 1086 (а должно быть ~4к). О чем это говорит нам? О том что авторизация является для нас боттлнеком, который замедляет работу системы (из-за сильной нагрузки на ЦПУ, что говорит о том, что алгоритм кеширования у нас не очень). Еще о том, что погрешности измерений огромные.
Коэффициент авторизации позволит вам не только оценить работу алгоритмов авторизации, но и очертить границы в которых может работать весь ваш комплекс микросервисов, а так же сообщить вам — имеет ли смысл оптимизировать код конкретного микросервиса или нет, потому что может так оказаться, что выигрыш будет 0.
Если же всего лишь включить роль в JWT токен, то с 12 потоками клиента можно получить от dummy среднее 6396, минимум 6372, максимум 6444. Т.е. Ка1 оказался равен 2.8!
А что будет, если отключить кеширование на клиенте, не использовать роли JWT и оставить его только на ролевой модели? Производительность вырастет, потому что сетевые задержки около нулевые и нагрузка на ЦПУ для dummy станет минимальной — среднее 3817, минимум 3806, максимум 3828, что говорит нам о Ка1 = 4.7. Однако следует учитывать, что такое решение не будет масштабируемым, потому что каждый клиент будет обращаться постоянно к сервису ролевой модели и увеличивать на него нагрузку, уже при сотне под начнутся серьезные проблемы, делающие невозможной работу авторизации, разве что у вас на каждый сервис, которому нужна авторизация будет пода авторизации, которая эту функцию будет выполнять, есть в интернете такие сетевые инженеры, которые любую проблему готовы
решить добавив под.
А выпустить кракена так и не удалось, потому что железо не выдержит испытаний. Может быть в другой раз, когда будет бюджет недельку-другую погонять кластер на сотню машинок по 2-4 ядра с парой гиг памяти.
3 Как использовать обобщенную модель данных
Теперь, определившись с терминами, можно разобрать несколько задачек, для того, что бы видеть как на практике применить материал.
1 Закрытый онлайн аукцион
Организатор может создать аукцион, пригласить участников. Участник может принять приглашение, сделать ставку.
Для того, что бы организатор мог создавать аукционы — нужно создать глобальную роль Организатор и при попытке создать аукцион — требовать эту роль. Созданные приглашения уже хранят в себе идентификаторы пользователей, поэтому когда пользователь делает ставку в аукционе, то это будет простейший запрос наличия записи перед вставкой ставки в аукцион.
2 Логистика
Огромная логистическая компания требует разграничить доступы для супервизоров и продавцов да еще с учетом региона. Работа такова, что продавец может выставить заявку на получение товара, а супервизор уже решает кому и сколько достанется. Соответственно продавец может видеть свой магазин и все товары в нем, а так же созданные им заявки, статус их обработки. Супервизор может видеть все магазины региона, в котором он работает, их заявки и историю исполнения заявок, так же он может перевести заявку в состояние исполнения для непосредственно доставки в магазин нужного товара.
Для реализации такого функционала нам потребуется реестр регионов и магазинов в качестве отдельного микросервиса, назовем его С1. Заявки и историю будем хранить на С2. Авторизация — А.
Далее при обращении продавца для получения списка его магазинов (а у него может быть их несколько), С1 вернет только те, в которых у него есть меппинг (Пользователь, Магазин), так как ни в какие регионы он не добавлен и для продавца регионы всегда пустое множество. Разумеется при условии, что у пользователя есть разрешение просматривать список магазинов — посредством микросервиса А.
При получении заявок магазина, проверка в А разрешений смотреть заявки, а затем С2 отравляет запрос в С1 и получает разрешение или запрет на доступ к магазину.
Работа супервизора будет выглядеть немного иначе, вместо регистрации супервизора на каждый магазин региона, мы сделаем меппинги (Пользователь, Регион) и (Регион, Магазин) в этом случае для супервизора у нас всегда будет список актуальных магазинов с которыми он работает.
В таком случае, когда супервизор решит перевести заявку на поставку в исполнение, то после проверки, что у него есть разрешение в А, С2 отправит проверку, что у супервизора есть доступ к магазину.
3 Секретные части документа
Некое министерство обязано выкладывать документы в общественный доступ, но часть документа является не предназначенной для показа любому желающему (назовем эту часть — номер телефона). Сам документ состоит из блоков, каждый из которых может быть либо текстом, либо номером телефона — скрытой частью, которую видеть могут только особые пользователи, подписавшие соглашение о неразглашении.
Когда пользователь обращается в сервис для получения блоков документа, микросервис в авторизации проверяет роль пользователя на чтение документов, далее в БД каждый блок имеет флаг — секрет. У документа есть меппинг (Пользователь, Документ) — список пользователей, которые подписали соглашение. В этом случае при получении из БД блоков документа можно сразу отфильтровать невидимые для пользователя блоки одним запросом.
4 Команда и ее проекты
Если у вас большая команда, и много проектов, и такая команда у вас не одна, то координировать работу их будет той еще задачей. Особенно если таких команд у вас тысячи. Каждому разработчику вы доступы не пропишите, а если у вас человек еще и в нескольких командах работает, то разграничивать доступ станет еще сложнее. Например если 2 команды работают над одним проектом, и разработчик в обоих командах присутствует, из одной его пнули, как теперь определять актуальный состав его проектов?
Такую проблему проще всего решить при помощи групп.
Группа будет объединять все необходимые проекты в одно целое. При добавлении участника в команду, добавляем меппинг (Пользователь, Группа, Роль).
Допустим, что Вася — разработчик и ему нужно вызвать метод develop на микросервисе для выполнения своих обязанностей. Этот метод потребует у Васи роли в проекте — Разработчик.
Как мы уже договаривались — регистрация пользователя в каждый проект для нас недопустима. Поэтому микросервис проектов обратится в микросервис групп, что бы получить список групп, в которых Вася — Разработчик. Получив список этих групп можно легко проверить уже в БД микросервиса проектов — есть ли у проекта какая-нибудь из полученных групп и на основании этого предоставлять или запрещать ему доступ.
SPA (Single Page Application)
Вернемся к истории. В начале 10-х годов появились реактивные фреймворки, что, в свою очередь, подтолкнуло к развитию бэкенд-фреймворков. Бэкенд-фреймворки начали поставлять реактивные движки внутри себя, прямо «из коробки». А это дало возможность разрабатывать фронтенд независимо от бэкенда и отделять интерфейсы от бизнес-логики.
Преимущества SPA
Микросервисная архитектура — это некое развитие сервис-ориентированной архитектуры (SOA), направленное на взаимодействие небольших, слабо связанных и легко заменяемых модулей — микросервисов. Микросервис — это изолированная, слабосвязанная единица разработки, работающая над одной задачей.
Микросервисная архитектура получила развитие благодаря тому, что появились реактивные фреймворки, практики гибкой разработки и направление DevOps.
Разберем плюсы и минусы микросервисов.
Преимущества микросервисной архитектуры
Один из частных случаев проблемы взаимодействия между микросервисами мы сегодня как раз и рассмотрим. Для этого погрузимся в один пример.
Аутентификация и авторизация в проекте с микросервисной архитектурой
Рассмотрим частный случай проблемы с авторизацией и аутентификацией на примере реализации проекта с видеокурсами.
Контекст. Проект, реализованный с использованием микросервисной архитектуры. Пользователи могут загружать свои курсы и уроки, а внутри уроков загружать видео; другие пользователи, в зависимости от их уровня доступа, могут их смотреть. Проект разбили на три микросервиса:
Теперь нужно понять, как фронту взаимодействовать с этими тремя микросервисами. Начинается все с аутентификации — на этом этапе нужно понять, как и где ее делать. Есть несколько способов реализации.
Вариант 1. Аутентификация на каждом микросервисе
Аутентификация на каждом микросервисе. Реализация 1
Проблемы этого решения
Аутентификация на каждом микросервисе. Реализация 2
Выделение пользователей в отдельную БД.
Так мы решаем проблему с синхронизацией — ее делать не нужно. Но в этом случае есть другие проблемы.
Вариант 2. Работа с пользователями в отдельном микросервисе
Работа с пользователями в отдельном микросервисе. Реализация 1
Делать дополнительные запросы к микросервису Auth.
Работа с пользователями в отдельном микросервисе. Реализация 2
Все запросы отправлять через Auth. В этом случае фронту станет легче, так как ему не нужно будет думать, на какой сервис отправить запрос. Есть документация API и все запросы идут на один и тот же домен.
Тратится лишнее время. Теперь все запросы проходят через Auth — и те, что требуют аутентификацию, и те, что не требуют, то есть на каждый запрос к бэку у нас дополнительный запрос. В целом это нормально, но т. к. это отдельный сервис со своей БД и неким ядром сервиса (например, какой-либо фреймворк), то при каждом запросе, не требующем аутентификации, происходит инициализация ядра, делаются какие-то проверки, а это все требует времени.
Вариант 3. Паттерн API Gateway
Это, пожалуй, самый правильный вариант реализации аутентификации в проекте с микросервисной архитектурой.
Что такое API Gateway?
Это микросервис, который является шлюзом между клиентом и другими микросервисами, он принимает запросы и проксирует их дальше. Бывают разные вариации API Gateway, нас интересует Gateway Routes — шлюз, который используется как обратный прокси, перенаправляющий запросы клиента на соответствующий сервис.
Каким должен быть API Gateway?
В качестве API Gateway выберем Nginx — из-за его быстроты, доступности и многофункциональности. Теперь получается, что все запросы идут через него, а он их отправляет в нужные микросервисы. В конфигурации прописываем, на какие ресурсы нужен доступ пользователям, на каких не нужно проверять аутентификацию, какие запросы идут через Auth, а какие нет.
Как происходит аутентификация в этом случае?
Аутентификация учетных данных клиентов — важная задача, но этого недостаточно. Приложение должно также реализовать механизм авторизации, который проверяет, позволено ли клиенту выполнить запрошенную операцию. Как нам действовать в этом случае? Есть несколько вариантов.
Вариант 1. Авторизация на MS Auth
В этом случае микросервис сам решает, кому можно отправлять запрос, а кому нельзя. Вариантов здесь тоже два:
Авторизация на MS Auth. Реализация 1
Делаем от каждого MS запрос к MS Auth, чтобы проверить, есть ли доступ. Но здесь является проблемой то, что появляется еще один запрос.
Авторизация на MS Auth. Реализация 2
Определять на самом MS, можно ли обращаться к роуту. В этом случае у нас нет лишнего запроса, к тому же если у пользователя нет доступа, мы сразу можем реджектить — не отправлять MS. Но есть проблемы:
Вариант 2. Авторизация на ресурсных микросервисах
В этом случае ресурсные микросервисы сами решают, кому можно, а кому нельзя выдавать права. Как это можно сделать?
JWT-токены позволяют передавать полезную нагрузку — некие данные от одного микросервиса к другому. И мы можем передать информацию: про роль, про самого пользователя и нам не нужно будет каждый раз делать запрос к микросервису авторизации, чтобы узнать, есть доступ или нет. Таким образом, информацию про роли мы можем хранить на каждом микросервисе. И мы получаем от микросервиса авторизации информацию по пользователю и его роли. Как устроен сам токен? Мы передаем, в данном случае:
Главный минус JWT-токена заключается в том, что он автономен, если мы выдали JWT, мы его не можем отозвать, а это влияет на безопасность. Чтобы эту проблему обойти, обычно занижают время жизни токена до минимального. Тогда злоумышленникам сложнее будет использовать этот токен, но при этом пользователям будет не очень удобно пользоваться.
OAuth 2.0 выдает два вида токенов: access (тот же самый токен) и refresh (используется для обновления access). Access имеет короткий период жизни, а refresh — длинный (допустим, месяц), в этом случае через refresh можно обновлять access.
Межсервисная аутентификация
Существует два общих способа реализации межсервисной аутентификации:
В подходе mTLS каждый микросервис может уверенно определить, с кем он общается, в дополнение к достижению конфиденциальности и целостности передаваемых данных. Каждый микросервис при старте должен получать свою пару открытый/закрытый ключей и открытый ключ доверенного центра сертификации, которые в дальнейшем используются для аутентификации микросервиса получателя через mTLS. m TLS обычно реализуется с самохостинговой инфраструктурой открытых ключей. Основными проблемами при использовании mTLS являются обеспечение доступа к ключам и первичная загрузка ключей, отзыв сертификатов и ротация ключей.
Подход на основе токенов работает на прикладном уровне. Токен является контейнером и может содержать идентификатор вызывающего микросервиса (microservice id) и его разрешения (scopes). Вызвающий микросервис может получить токен, обращаясь к специальной службе токенов безопасности, используя свой собственный идентификатор и пароль, а затем присоединяя его к каждому исходящему запросу, например, через HTTP заголовки. В большинстве случаев аутентификация на основе токенов работает с использованием протокола TLS, что дополнительно обеспечивает конфиденциальность и целостность передаваемых данных.
Согласно ряду научных публикаций (например, Overcoming Security Challenges in Microservice Architectures) и нескольким докладам на ведущих конференциях по безопасности (например, A Pragmatic Approach for Internal Security Partnerships), mTLS является наиболее популярным вариантом аутентификации микросервисов.
Модель сетевой сегментации или межсетевой защиты не обеспечивает должного уровня безопасности при передаче данных между сервисами, и в настоящее время крайне редко используется на практике в виде единственного механизма защиты.
Социальный вход
Социальный вход или вход через авторитетный проверенный сайт — популярный и удобный способ идентификации. Он предназначен не только для входа в систему. У American Express есть Amex Express Checkout, откуда вы входите на свой Amex-аккаунт, чтобы безопасно оплачивать товары на сторонних сайтах. Вы идентифицированы, и уже не нужно отправлять данные кредитной карты продавцу.
Для многих сервисов это отличный способ идентификации. Для входящего это удобно только в том случае, если у него есть аккаунт в этом стороннем сервисе. Поэтому социальный вход всегда подразумевает запасной вариант.
Социальный вход также запрашивает разрешение третьей стороны, что может отпугивать и останавливать пользователей и не работает с брандмауэрами, блокирующими оригинальный сайт (например, корпоративные офисы).
Тем не менее
статья MailСhimp от 2012 года понятно объясняет, почему сайт был против социального входа (и, судя по всему, с тех пор не поменял позицию). Сервис аргументирует это тем, что социальный вход создает слишком много неудобств для пользователя. Даже при однократной регистрации в варианте социального входа и при запасном варианте входа пользователь должен запомнить, как именно он регистрировался в самом начале.
В чем-то я согласен с MailСhimp, но социальный вход сейчас для многих гораздо понятнее и удобнее. Подтверждение тому — широта его применения: часто это отличный способ упростить идентификацию. Я по-прежнему предлагал бы только один вариант, а именно социальный вход, но если такие компании, как Medium, предлагают несколько вариантов, такое решение точно имеет право на жизнь.
4 Проектируем микросервисы для работы чайников
Компания ОАО «ПьемЧай» ежедневно требует работы от миллиона сотрудников и сотни тысяч гостей. Все сотрудники пьют чай и в этом состоит их работа. В компании есть гости, которые пить чай не могут, для них доступны опции, которые позволяют им видеть какой чай они смогут пить на своей будущей работе, а так же лучших сотрудников года, месяца и недели. Некоторые сотрудники в пандемию работают удаленно и доступ к чаю им предоставляет курьерская служба Кракен, прямо к точке доставки. Удаленные сотрудники могут получать чай только из той точки доставки, к которой они привязаны. Находясь в офисе они все равно могут пить чай как обычные сотрудники.
2 Архитектура решения
Для решения поставленной задачи нам необходимы следующие микросервисы:
Графически это будет выглядеть так:
В качестве БД будем использовать PostgreSQL.
Предусмотрим следующие обязательные для решения задачи роли:
Биометрическая идентификация
Отпечатки пальцев, сканы сетчатки глаза, распознавание лица, голоса и многое другое — все это биометрическая авторизация.
Наиболее распространенный пример — Touch ID компании Apple. Такие вещи действительно восхищают. Биология — наша истинная идентичность, она всегда с нами. Мы знаем об идее разблокирования телефонов или планшетов при помощи отпечатка пальца. Тем не менее биометрическая идентификация используется и в других местах (и с другими параметрами).
Windows Hello — это перспективная система идентификации для Windows 10, соединяющая камеры с датчиками (на компьютерах и устройствах) для распознавания лица, радужки глаз или отпечатков пальцев. Нужно просто открыть компьютер и заниматься своими делами, не жертвуя при этом безопасностью. Этот тип идентификации был до недавнего времени невозможен, особенно в масштабе Windows 10.
Для работы биометрических систем нужны аппаратные средства и датчики, но, к счастью, в наших мобильных телефонах есть датчики для самых разных вещей. Hello использует инфракрасный датчик камеры для определения лица и глаз (при любом освещении), а в мобильных телефонах или планшетах есть устройство для сканирования отпечатков пальцев.
Если бы производители настольных компьютеров и ноутбуков уделяли больше внимания безопасности и биометрическим датчикам, мы бы давно уже ушли от паролей. Mobile с самого начала определил безопасность как приоритет, и теперь остальное программное обеспечение подгоняется под эти требования.
Биометрическая идентификация только начинает развиваться, но некоторые API и библиотеки позволяют нам пользоваться биометрической идентификацией уже сегодня. К ним относятся BioID Web Service, KeyLemon, Authentify и Windows Biometric Framework API (на котором, как мне кажется, построена Hello).
Истоки проблемы
Все мы не очень любим авторизацию через пароль. Чем больше сервисов мы используем, тем больше паролей приходится запоминать.
Приложения SaaS, социальные сети и другие службы требуют соблюдать строгие правила введения паролей, которые затрудняют вход в систему для честных пользователей. Неужели авторизация вида «имя пользователя и пароль» настолько незаменима, что мы готовы смириться с этим препятствием при использовании сервисов и продуктов?
Дело не в самих паролях — проблема заключается в масштабе, ведь людям приходится запоминать множество имен и паролей, они испытывают дискомфорт. А мы не хотим, чтобы наши продукты стали менее безопасными, когда мы понизим стандарты защиты в угоду удобству пользователей. Как же обеспечить надежную безопасную идентификацию и защиту конфиденциальных данных?
Для этого уже есть несколько методов и постоянно появляются новые. Традиционную аутентификацию при помощи пароля можно сделать комфортной и удобной. Вот актуальные способы:
Я буду оценивать каждый метод, исходя из нескольких факторов:
Архитектурные модели реализации АА
Мы провели декомпозицию функций АА (если собираешься стать архитектором безопасности приложений, то добавляй сложные слова и термины в свою коллекцию – возможно, они пригодятся на совещаниях) на основе характеристик типовых микросервисных приложений и определили следующий список подфункций безопасности (Рисунок 1): пограничная авторизация (edge-level authorization), авторизация на уровне сервиса (service-level authorization), пробрасывание идентификатора внешнего субъекта (external entity identity propagation), межсервисная аутентификация (service-to-service authentication). Затем мы рассмотрели основные электронные базы данных и библиотеки, а также стандарты безопасности и презентации на основных конференциях по безопасности с целью выявления существующих архитектурных схем.
Рисунок 1. Подфункции аутентификации и авторизации в системах на базе микросервисов
Разберем основные модели и их схемы.
2 Обобщенная модель данных
Прежде чем проектировать, необходимо договориться о терминах и структурах данных с их взаимосвязями.
Вы можете убрать ненужные вам связи, главное — это то, что вам необходимо ограничивать.
Детально опишем все имеющиеся определения с которыми будем дальше работать.
1 Пользователь
Субъект, чей доступ необходимо авторизовать.
Данное определение задает субъекты, которые могут быть как людьми, так и автоматическими системами, которые получают доступ к вашим ресурсам. У любого пользователя могут быть свои роли, разрешения и группы.
2 Сервис
Множество ресурсов объединенных в единое целое, как пример сервис проектов.
В рамках микросервисной архитектуры основным направлением разработки является выделение таких множеств ресурсов, которые можно назвать сервисом, так что бы программно-аппаратная часть могла эффективно обрабатывать заданный объем данных.
3 Ресурс
Единичный объем информации для работы авторизации, например проект.
В рамках сервиса могут существовать ресурсы, доступ к которым необходимо ограничивать. Это может быть как файл в облачном сервисе, так и заметка, видимая ограниченному кругу лиц.
4 Разрешение
Право пользователя выполнять операцию над сервисом и/или ресурсом.
5 Роль
Множество разрешений, по сути под словом роль всегда подразумевается множество разрешений.
Следует отметить, что в системе может не быть ролей и напрямую задаваться набор разрешений для каждого пользователя в отдельности. Так же в системе могут отсутствовать разрешения (речь про хранение их в виде записей БД), но быть роли, при этом такие роли будут называться статичными, а если в системе существуют разрешения, тогда роли называются динамическими, так как можно в любой момент поменять, создать или удалить любую роль так, что система все равно продолжит функционировать.
Ролевые модели позволяют как выполнять вертикальное, так и горизонтальное разграничение доступа (описание ниже). Из типа разграничения доступа следует, что сами роли делятся на типы:
Но отсюда следует вопрос, если у пользователя есть глобальная роль и локальная, то как определить его эффективные разрешения? Поэтому авторизация должна быть в виде одной из форм:
Подробное описание использования типа ролей и формы авторизации ниже.
Роль имеет следующие связи:
Следует отметить, что реализация статичных ролей требует меньше вычислительных ресурсов (при определении эффективных разрешений пользователя будет на один джойн меньше), но вносить изменения в такую систему можно только релизным циклом, однако при большом числе ролей гораздо выгоднее использовать разрешения, так как чаще всего микросервису нужно строго ограниченное их число, а ролей с разрешением может быть бесконечное число. Для больших проектов, стоит задуматься о том, что бы работать только с динамическими ролями.
6 Группа
Используя группы можно объединить множество ресурсов, в том числе расположенных в разных сервисах в одно целое, и управлять доступом к ним используя одну точку. Это позволяет гораздо проще и быстрее реализовывать предоставление доступа пользователя к большим массивам информации, не требуя избыточных данных в виде записи на каждый доступ к каждому ресурсу по отдельности вручную или автоматически. По сути вы решаете задачу предоставления доступа к N ресурсам создавая 1 запись.
Группы используются исключительно для горизонтального разграничения доступа (описание ниже). Даже если вы будете использовать группы для доступа к сервисам, то это все равно горизонтальное разграничение доступа, потому что сервис — это совокупность ресурсов.
Группа имеет следующие связи:
7 Вертикальное и горизонтальное разграничение доступа.
Самым простым способом представить себе работу авторизации — это нарисовать таблицы на каждого пользователя и каждый сервис, где колонки будут задавать разрешения, а строки — ресурсы, на пересечении ставятся галочки там, где доступ разрешен (привет excel-warrior’ам).
Для обеспечения доступа вы можете либо связать пользователя с ролью, что даст вам заполнение соответствующих разрешению ролей колонок в таблицах — такое разграничение называется вертикальным. Либо вы можете связать пользователя, роль и ресурс, что ограничит доступ до отдельного ресурса — такое предоставление доступ является горизонтальным. Вторым вариантом горизонтального доступа являются группы, когда вы заполняете множество строк соответствующими разрешениями, когда включаете пользователя в эту группу.
8 Глобальность/локальность авторизации доступа в микросервисах
Из-за того, что у теперь у нас существуют два варианта наборов разрешений пользователя, то можно выделить два варианта, как объединить все вместе:
Одним из важных преимуществ конъюнктивной формы является жесткий контроль за всеми операциями, которые может выполнять пользователь, а именно — без глобального разрешения пользователь не сможет получить доступ в следствие ошибки на месте. Так же реализация в виде программного продукта горазо проще, так как достаточно сделать последовательность проверок, каждая из которых либо успешна, либо бросает исключение.
Дизъюнктивная форма позволяет гораздо проще делать супер-админов и контролировать их численность, однако на уровне отдельных сервисов потребует написания своих алгортмов авторизации, которые в начале получит все разрешения пользователя, а уже потом либо успешно пройдет, либо бросит исключение. Однако преимуществом является тот факт, что можно использовать первый положительный ответ, что бы дать зеленый свет запросу.
Рекомендуется всегда использовать только конъюнктивную форму авторизации в виду ее большей гибкости и возможности снизить вероятность появления инцидентов по утечке данных. Так же именно конъюнктивная форма авторизации имеет большую устойчивость к ДДОС атакам в виду использования меньшего объема ресурсов. Ее проще реализовать и использовать, отлаживать. Разумеется можно и дизъюнктивную форму натравить на анализ аннотаций метода и поиск соответствующих сервисов, но запросы вы отправлять будете скорее всего синхронно, один за другим, если же будете делать асинхронные вызовы, то много ресурсов будет уходить в пустоту, оно вам надо?
10 О кешировании данных
Предложенная модель дает возможность сделать масштабируемую систему авторизации. Позволяет сделать глобальное разграничение один раз и далее только корректировать, добавляя новые роли, разрешения, группы, все более детализируя доступ к каждому конкретному ресурсу каждому пользователю.
Архитектору безопасности на заметку
Задача данного исследования и подготовленного обзора заключается в том, чтобы предоставить Архитектору безопасности лучшие практики для реализации модели АА в разрабатываемом продукте и оставить его наедине с вопросом: «Что из этого лучше подходит к моему приложению?». Используя преимущества и недостатки, отмеченные в этом материалы, Архитектор, может аргументировать свой выбор и разработать стратегию для реализации АА в рамках своего продукта.
При этом, мы не исключаем, что на этот же вопрос «Что из этого лучше подходит к моему приложению?» Архитектор ответит: «Кажется, что ничего не подходит. Придется делать свою модель с блэк-джеком». И в итоге, разработанная им модель окажется в данном списке в качестве новой «best practice» — смело делай pull requests в соответствующую шпаргалку от OWASP.
В полном тексте научной публикации, помимо рекомендаций архитектору по безопасности приложений по выбору подходящего архитектурного шаблона, можно найти полный перечень источников информации (публикации, выступления на конференциях), которые были проанализированы в рамках данного исследования.
Что представляет из себя база данных.
Выше я писал про чудесный “текстовый файл”, в котором хранятся все данные пользователей. Вы безусловно можете организовать хранение данных в обычных .txt файлах, но на практике так никто не делает. Данная формулировка была использована, для того чтобы вы понимали, что ваши данные хранятся на жестком диске, таким же образом, как вы храните у себя на компьютере фотки, записи и видео.
Но используют для этих целей определенные программы “Базы данных”. База данных – это программа, которая работает в фоновом режиме, функциями которой вы можете пользоваться из других программ (написанных вами). Что это за функции? – если коротко, то это операции сохранения и получения данных, но в отличии от обычного текстового файла, база данных выполняет операции сохранения и получение намного быстрее (Особенно когда этих данных становится очень много).
Таким образом работу backend приложения можно представить, как работу 2-х независимых программ:
Что же теперь делать
Все изменения должны быть удобны для пользователей. Мы можем упрощать коммуникации, уменьшив количество паролей, которых требуют наши сервисы и приложения. Если требуется внедрить новые способы идентификации для большего комфорта пользователей, нужно всегда рассматривать такую возможность.
Будь моя воля, мы бы навсегда покончили с паролями. Мне кажется, что они тянут нас назад, хотя и еще остаются нужны. Так что нас ждет революция в области паролей.
Тем не менее нужно помнить, что люди хотят чувствовать себя в безопасности, когда входят в систему, и знать, что их данные недоступны посторонним. Если мы будем пренебрегать идентификацией, пользователи не будут нам доверять. Поэтому мы вовсе не собираемся устранить все пароли уже завтра, хотя, возможно, сократим масштаб их применения.
Лучшая идентификация, как и лучший интерфейс, абсолютно невидима. Нужно стремиться к тому, чтобы сделать идентификацию незаметной. А это значит, что традиционная идентификация пароля — независимо от того, насколько серьезна ее функциональность, — это вчерашний день.
Надеюсь, мы застанем время, когда авторизация перестанет быть препятствием, но при этом вся информация будет оставаться в безопасности. Если вы уже думаете об этом — знайте, что скоро так и случится. Я думаю, это будут решения из области биометрии, и многие со мной согласны. В любом случае, работая над созданием удобных сервисов с безопасный входом, мы сделаем идентификацию комфортнее.
Теория. Виды архитектуры
Начнем с теории и рассмотрим наиболее популярные виды архитектур.
Монолитная архитектура
В нулевых годах появились первые языки веб-разработки (например, PHP), различные CMS и фреймворки (например, jQuery, который сейчас уже все ненавидят). И большинство проектов реализовывались именно в виде монолита.
Основная особенность монолитной архитектуры в том, что все, грубо говоря, находится «в куче»: интерфейс, бизнес-логика и слой доступа к данным. Разберем признаки монолитной архитектуры подробнее и поговорим о ее преимуществах и недостатках.