Максимально безопасная авторизация. Обсуждение алгоритма авторизации клиентов на сервере / Хабр

Основные проблемы

У злоумышленника будет всего лишь 30 секунд на авторизацию по этому хэшу и из-за того, что мы подсолили наш хэш айпишником, он обязательно должен отправить этот хэш с того же внешнего IP адреса, что очень сильно усложняет ему работу, если он не находится в той же сети с жертвой.

Тут у меня уже вопрос к знающим. Может ли злоумышленник перехватить управление потоком связи на себя, чтобы при этом сервер не заметил подмены клиента?

. Помните о том, что обозначать ошибки одним лишь цветом может быть недостаточно.

Во многом, вопрос выделения сделанных пользователем ошибок дополнительными средствами, не относящимися к привычному цветовому обозначению, зависит от масштабов вашего проекта и количества существующей и потенциальной аудитории. Дело в том, что расстройства цветового восприятия у пользователей распространены

шире, чем мы привыкли о них думать

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

Будет здорово, если вы уделите им немного внимания и облегчите их задачи.
Говоря о дополнительных средствах, которыми можно обозначить сделанные пользователем ошибки, мы имеем в виду такие простые символы, как треугольник с восклицательным знаком, заметный крест рядом с полем, содержащим ошибку, и другие подобные визуальные обозначения.

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

Похожее:  Аутентификация, авторизация и учет (AAA) – RADIUS или TACACS

Регистрационная форма PayPal в полноцветном режиме.   
Как мы видим, в полноцветной реальности соответствующим образом обозначены все поля, а не только поле для капчи. Однако, тот самый треугольник, который в любом случае сообщит посетителю с расстройством восприятия цвета об ошибке, находится только в одном поле.

Новая регистрационная форма PayPal однозначным образом сообщает пользователю об ошибке вне зависимости от того, способен ли он различать цвета. Как и подход к дизайну в целом, способы создания современных и актуальных регистрационных форм постоянно претерпевают изменения.

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

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

1 Словесное описание решаемой задачи

Компания ОАО «ПьемЧай» ежедневно требует работы от миллиона сотрудников и сотни тысяч гостей. Все сотрудники пьют чай и в этом состоит их работа. В компании есть гости, которые пить чай не могут, для них доступны опции, которые позволяют им видеть какой чай они смогут пить на своей будущей работе, а так же лучших сотрудников года, месяца и недели.

Некоторые сотрудники в пандемию работают удаленно и доступ к чаю им предоставляет курьерская служба Кракен, прямо к точке доставки. Удаленные сотрудники могут получать чай только из той точки доставки, к которой они привязаны. Находясь в офисе они все равно могут пить чай как обычные сотрудники.

Что такое сессии?


Попробую рассказать в паре абзацев.

Сессии – это механизм, который позволяет однозначно идентифицировать пользователя.
По-человечески это значит, что для каждого посетителя сайта можно создать уникальное “хранилище”, к которому будет доступ только у этого самого посетителя.
Хранилище это хранится в файле на сервере.

На самом деле сессии хранятся не обязательно в файлах. Например, cms Modx хранит их базе данных.
Но сейчас нам это не важно, главное, что сессии предоставляют удобный способ работать с данными, уникальными для пользователя.
Для нас сессия выглядит как обычный ассоциативный массив под названием $_SESSION, в разные поля которого можно записать хоть число, хоть строку, хоть сериализованный объект.

Лучший способ авторизации – это ее отсутствие.

Да, наш первый тезис является банальной и основной истиной UX – чем меньше действий требуется от пользователя, тем лучше. Зачастую, пользуясь некоторыми сайтами, у меня возникает вопрос: «Почему я должен регистрироваться здесь ради того, чтобы разово воспользоваться определенной услугой?».

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

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

Если это так, то в первую очередь рассмотрите наиболее простой и быстрый способ авторизации, а именно использование модулей социальных сетей, повсеместно распространенных в сети на данный момент и обеспечивающих аутентификацию пользователя в один клик.

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

1 Время восстановления/энтропия входных параметров

Авторизация принимает решение о разграничении доступа на основе множества входных параметров. Если таковых будет слишком много, либо мерность множеств окажется слишком большой, то авторизация будет терять слишком много ресурсов на выполнение ненужных операций. Это как сортировать данные пузырьком и qsort. Не следует выполнять ненужные операции.

Если у вашей системы есть на входе A,B,C,D,E,F — факты о пользователе, то если вы будете объединять все в одно, то получите A * B * C * D * E * F комбинаций, которые невозможно эффективно кешировать. По возможности следует найти такую комбинацию входных, что бы у вас было A * B * C и D * E * F комбинаций, а еще лучше A * B, C * D, E * F, которые вы уже легко сможете вычислять и кешировать.

Эта характеристика очень важна так же для построения системы правил, которые будут предоставлять пользователям доступы.

2 Детализация авторизации

Второй характеристикой является предел детализации авторизации, когда дальнейшее разграничение доступа становится уже невозможным. Например вы можете разграничивать доступ к ручкам микросервиса, но уже не иметь возможности ограничить доступ к сущностям, которые она выдает. Либо доступ к сущности вы ограничиваете, но вот операции доступны все и всем. И т.д.

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

2 обобщенная модель данных

Прежде чем проектировать, необходимо договориться о терминах и структурах данных с их взаимосвязями.

Максимально безопасная авторизация. Обсуждение алгоритма авторизации клиентов на сервере / Хабр

Вы можете убрать ненужные вам связи, главное — это то, что вам необходимо ограничивать.


Детально опишем все имеющиеся определения с которыми будем дальше работать.

Электронная почта должна быть альтернативой любому другому идентификатору пользователя.

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

В целом, это просто замечательная идея – дать возможность пользователю авторизироваться как с помощью почты, так и с помощью уникального имени. Большой плюс такого подхода во многом связан с тем, что электронная почта и пароль – это крепкая связка, живущая в сознании пользователя.

10 О кешировании данных

Основной проблемой при работе авторизации является точка в которой необходимо кешировать результаты, что бы работало быстрее все, да еще желательно так, что бы нагрузка на ЦПУ не была высокой. Вы можете поместить все ваши данные в память и спокойно их читать, но это дорогое решение и не все готовы будут себе его позволить, особенно если требуется всего лишь пара ТБ ОЗУ.

Правильным решением было бы найти такие места, которые бы позволяли с минимальными затратами по памяти давать максимум быстродействия.

Предлагаю решить такую задачу на примере ролей пользователя и некоего микросервиса, которому нужно проверять наличие роли у пользователя. Разумеется в данном случае можно сделать карту (Пользователь, Роль) -> Boolean. Проблема в том, что все равно придется на каждую пару делать запрос на удаленный сервис.

Даже если вам данные будут предоставлять за 0,1 мс, то ваш код будет работать все равно медленно. Очевидным решением будет кешировать сразу роли пользователя! В итоге у нас будет кеш Пользователь -> Роль[]. При таком подходе на какое-то время микросервис сможет обрабатывать запросы от пользователя без необходимости нагружать другие микросервисы.

Разумеется читатель спросит, а что если ролей у пользователя десятки тысяч? Ваш микросервис всегда работает с ограниченным количеством ролей, которые он проверяет, соответственно вы всегда можете либо захардкодить список, либо найти все аннотации, собрать все используемые роли и фильтровать только их.

Полагаю, что ход мыслей, которому стоит следовать, стал понятен.

5 Роль

Множество разрешений, по сути под словом роль всегда подразумевается множество разрешений.

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


Ролевые модели позволяют как выполнять вертикальное, так и горизонтальное разграничение доступа (описание ниже). Из типа разграничения доступа следует, что сами роли делятся на типы:

Но отсюда следует вопрос, если у пользователя есть глобальная роль и локальная, то как определить его эффективные разрешения? Поэтому авторизация должна быть в виде одной из форм:

Подробное описание использования типа ролей и формы авторизации ниже.

Роль имеет следующие связи:

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

6 Группа

Используя группы можно объединить множество ресурсов, в том числе расположенных в разных сервисах в одно целое, и управлять доступом к ним используя одну точку. Это позволяет гораздо проще и быстрее реализовывать предоставление доступа пользователя к большим массивам информации, не требуя избыточных данных в виде записи на каждый доступ к каждому ресурсу по отдельности вручную или автоматически. По сути вы решаете задачу предоставления доступа к N ресурсам создавая 1 запись.

Группы используются исключительно для горизонтального разграничения доступа (описание ниже). Даже если вы будете использовать группы для доступа к сервисам, то это все равно горизонтальное разграничение доступа, потому что сервис — это совокупность ресурсов.


Группа имеет следующие связи:

7 Вертикальное и горизонтальное разграничение доступа.

Самым простым способом представить себе работу авторизации — это нарисовать таблицы на каждого пользователя и каждый сервис, где колонки будут задавать разрешения, а строки — ресурсы, на пересечении ставятся галочки там, где доступ разрешен (привет excel-warrior’ам).

Для обеспечения доступа вы можете либо связать пользователя с ролью, что даст вам заполнение соответствующих разрешению ролей колонок в таблицах — такое разграничение называется вертикальным. Либо вы можете связать пользователя, роль и ресурс, что ограничит доступ до отдельного ресурса — такое предоставление доступ является горизонтальным.

8 Глобальность/локальность авторизации доступа в микросервисах

Несмотря на то, что все роли могут хранится в единой БД, то вот связи между ними и пользователями хранить все вместе на всю вашу огромную систему — это типичный антипаттерн, делать так является грубейшей ошибкой, это все равно что POSIX права на файлы хранить в облачном сервисе, вместе с таблицей inode.

9 Конъюнктивная/дизъюнктивная форма авторизации


Из-за того, что у теперь у нас существуют два варианта наборов разрешений пользователя, то можно выделить два варианта, как объединить все вместе:

Одним из важных преимуществ конъюнктивной формы является жесткий контроль за всеми операциями, которые может выполнять пользователь, а именно — без глобального разрешения пользователь не сможет получить доступ в следствие ошибки на месте. Так же реализация в виде программного продукта горазо проще, так как достаточно сделать последовательность проверок, каждая из которых либо успешна, либо бросает исключение.

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

Рекомендуется всегда использовать только конъюнктивную форму авторизации в виду ее большей гибкости и возможности снизить вероятность появления инцидентов по утечке данных. Так же именно конъюнктивная форма авторизации имеет большую устойчивость к ДДОС атакам в виду использования меньшего объема ресурсов.

Ее проще реализовать и использовать, отлаживать. Разумеется можно и дизъюнктивную форму натравить на анализ аннотаций метода и поиск соответствующих сервисов, но запросы вы отправлять будете скорее всего синхронно, один за другим, если же будете делать асинхронные вызовы, то много ресурсов будет уходить в пустоту, оно вам надо?

Возможность быстрого переключения между формами авторизации и регистрации.

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

Максимально компактное и близкое расположение форм регистрации и входа на сайте журнала TheVerge.

Механизм смены пароля

Хоть данное действие и происходит редко, но есть шанс, что новый пароль будет перехвачен именно через его смену. Я долго осматривал данный участок и не смог придумать ничего лучше, чем воспользоваться SSL/TSL соединением для защиты хэша нового пароля.

Можно попробовать сделать механизм смены пароля по СМС. Клиент будет присылать СМС-сообщение на какой-то указанный номер с новым паролем. Если система требует серьезной защиты, то данный механизм можно и использовать.

1 Закрытый онлайн аукцион


Организатор может создать аукцион, пригласить участников. Участник может принять приглашение, сделать ставку.

Для того, что бы организатор мог создавать аукционы — нужно создать глобальную роль Организатор и при попытке создать аукцион — требовать эту роль. Созданные приглашения уже хранят в себе идентификаторы пользователей, поэтому когда пользователь делает ставку в аукционе, то это будет простейший запрос наличия записи перед вставкой ставки в аукцион.

2 Логистика

Огромная логистическая компания требует разграничить доступы для супервизоров и продавцов да еще с учетом региона. Работа такова, что продавец может выставить заявку на получение товара, а супервизор уже решает кому и сколько достанется. Соответственно продавец может видеть свой магазин и все товары в нем, а так же созданные им заявки, статус их обработки.

Для реализации такого функционала нам потребуется реестр регионов и магазинов в качестве отдельного микросервиса, назовем его С1. Заявки и историю будем хранить на С2. Авторизация — А.Далее при обращении продавца для получения списка его магазинов (а у него может быть их несколько)

, С1 вернет только те, в которых у него есть меппинг (Пользователь, Магазин), так как ни в какие регионы он не добавлен и для продавца регионы всегда пустое множество. Разумеется при условии, что у пользователя есть разрешение просматривать список магазинов — посредством микросервиса А.

Работа супервизора будет выглядеть немного иначе, вместо регистрации супервизора на каждый магазин региона, мы сделаем меппинги (Пользователь, Регион) и (Регион, Магазин) в этом случае для супервизора у нас всегда будет список актуальных магазинов с которыми он работает.

3 Секретные части документа

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

Когда пользователь обращается в сервис для получения блоков документа, микросервис в авторизации проверяет роль пользователя на чтение документов, далее в БД каждый блок имеет флаг — секрет. У документа есть меппинг (Пользователь, Документ) — список пользователей, которые подписали соглашение.

4 Команда и ее проекты

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

Такую проблему проще всего решить при помощи групп.Группа будет объединять все необходимые проекты в одно целое. При добавлении участника в команду, добавляем меппинг (Пользователь, Группа, Роль).

Допустим, что Вася — разработчик и ему нужно вызвать метод develop на микросервисе для выполнения своих обязанностей. Этот метод потребует у Васи роли в проекте — Разработчик.Как мы уже договаривались — регистрация пользователя в каждый проект для нас недопустима.

Поэтому микросервис проектов обратится в микросервис групп, что бы получить список групп, в которых Вася — Разработчик. Получив список этих групп можно легко проверить уже в БД микросервиса проектов — есть ли у проекта какая-нибудь из полученных групп и на основании этого предоставлять или запрещать ему доступ.

Простой и лаконичный язык.

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

Так или иначе, существует несколько разных подходов к выбору надписей на кнопках. Определенно, в большинстве случаев наиболее оправданным является использование лаконичных и однозначных надписей, таких как «Вход», «Войти», «Создать», «Присоединиться» и «Зарегистрироваться».

Однако если вы стремитесь создать определенный эффект, то вполне допустимо уходить от лаконичных формулировок к более красочным, таким как «Стать участником», «Войти в мир» и так далее.
Стоит заметить, что при наличии времени и ресурсов проведение AB тестирования всегда будет полезным.
В качестве примера того, как формируются и меняются пользовательские предпочтения, можно привести опрос

а, демонстрирующий популярность различных способов обозначения кнопки авторизации в Соединенных Штатах и Великобритании. Надеемся, что скоро подобная аналитика станет привычной и для рунета.

«SignIn» все чаще используется вместо любых других формулировок.   

2 Архитектура решения

Для решения поставленной задачи нам необходимы следующие микросервисы:

  1. Ролевая модель для глобальной авторизации запросов
  2. Чайный сервис для предоставления возможности пить чай и получать статистику по выпитому
  3. Кракен — гейт с проверкой доступа к точке, все остальные проверки совершит чайный сервис


Графически это будет выглядеть так:

Максимально безопасная авторизация. Обсуждение алгоритма авторизации клиентов на сервере / Хабр

В качестве БД будем использовать PostgreSQL.Предусмотрим следующие обязательные для решения задачи роли:

  1. Сотрудник — для возможности пить чай;
  2. Удаленный сотрудник — для доступа к микросервису кракена (так как сотрудники в офисе не должны иметь возможности пить чай через точки распрастранения чая);
  3. Кракен — учетная запись микросервиса, что бы была возможность обращаться к API чайного сервиса;
  4. Авторизационная учетная запись — для предоставления доступа микросервисов к ролевой модели.

5 реализация микросервисов

Для реализации воспользуемся Spring фреймворком, он довольно медленный, но зато на нем легко и быстро можно реализовывать приложения. Так как за перформансом мы не гонимся, то попробуем на нем достичь скромных 1к рпс авторизованных пустых запросов (хотя люди на спринге умудрялись 100к пустых запросов проворачивать [1]).

Весь проект поделен на несколько репозиториев:

Для начала разберемся с базой данных ролевой модели:

Максимально безопасная авторизация. Обсуждение алгоритма авторизации клиентов на сервере / Хабр

Совместимость форм авторизации с менеджерами паролей различных браузеров.

Менеджеры паролей, интегрированные в браузеры – великое изобретение, колоссально облегчающее использование интернета. Они стали настолько привычной частью нашей повседневной жизни, что мы давно перестали думать о них как о таковых. Мы просто воспринимаем как должное тот факт, что после единичной авторизации на каком-либо сайте нам не придется делать это повторно, мы привыкли видеть формы, заполненные автоматически, и мы начинаем чувствовать себя очень некомфортно, когда обнаруживаем, что форма на сайте, на котором мы уже авторизовывались, оказывается пустой.

Учитывая все это, тестирование формы авторизации с менеджерами паролей различных браузеров – необходимость, которой нельзя пренебрегать. Конечно, кроме интегрированных в браузер менеджеров пользователи вполне могут пользоваться и сторонними менеджерами, но, как правило, при условии, что ваша форма корректно взаимодействует со всеми широко распространенными браузерами, она будет корректно заполняться и сторонним менеджером паролей.

Предупреждение и автоматическое исправление ошибок ввода.

Пользователи очень часто делают ошибки при заполнении форм. Характерно, что часто ошибки, сделанные пользователем, являются для него неочевидными, даже если это банальный ввод с неправильной раскладкой или пропущенная буква в пароле. Работать с пользовательскими ошибками мы должны сразу в двух направлениях – внятно оповещать пользователя, обозначая ошибки, и автоматически исправлять то, что возможно исправить.

Что касается оповещений, то набор из предупреждения о включенном Caps Lock, неправильной раскладке или недопустимых символах является базовым – пренебрегать им никак нельзя, ради обеспечения комфорта пользователя вы должны указывать на все без исключения ошибки.

Исправление опечаток и ошибок ввода в автоматическом режиме – достаточно неоднозначная и спорная тема. Наиболее корректно автоматическое исправление в формах может работать с опечатками при указании пользователем электронной почты. Пропущенные буквы в домене или отсутствие точки вполне можно исправлять при помощи автоматического алгоритма, не опасаясь исправить что-либо, введенное пользователем правильно.

Стоит ли принуждать пользователей к выбору “подходящего” пароля?

Это еще один вопрос, вызывающий споры среди веб-разработчиков. Для начала следует признать, что, несмотря на все предупреждения, средний пользователь по-прежнему не придает должного значения придумыванию устойчивого и сложного пароля. Как быть с этим фактом – команда каждого сайта решает сама.

Можно наблюдать, как по-разному ведут себя формы регистрации на различных сайтах, когда вопрос заходит о вводе пароля. Какие-то формы абсолютно не требовательны к пользователю и принципиально не обременяют его необходимостью соблюдать какие-либо правила, другие – напротив, делают все, чтобы заставить пользователя придумать действительно надежный пароль.

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

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

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

В то же время, алгоритм вполне может устанавливать некий критический порог, который пользователь должен преодолеть, иначе пароль будет считаться слишком простым и не будет принят системой. Этот подход широко используется на самых разнообразных сайтах.

Классическое сопровождение ввода цветовой индикацией на примере Яндекс.Почты.
Кроме контроля сложности и ограничения минимального количества символов, применяется также еще один довольно любопытный способ, заключающийся в анализе и сопоставлении пользовательского пароля с базой самый популярных паролей в мире, насчитывающей 10 тысяч комбинаций. В случае если вводимый пользователем пароль не оригинален и является одним из самых распространенных, то пользователь получает соответствующее предупреждение и предложение выбрать другую комбинацию.
регистрация, авторизация

«Thatpasswordistoocommon» – оповещение на Discourse, сообщающее о том, что выбранный пользователем пароль слишком простой и распространенный. Тем не менее, обратная сторона все подобных действий, направленных на «воспитание» пользователя – практически гарантированное раздражение от опытных пользователей, трезво оценивающих ситуацию и принимающих самостоятельно решение о том, стоит ли в данном случае обойтись простым, символическим паролем, или же необходимо использовать более сложный.

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

Оставляйте возможность переключаться между полями ввода с помощью клавиши «Tab» и выделяйте элементы при таком переключении.

Да, несмотря ни на что, пользователи, все еще переключающиеся между полями формы при помощи клавиши «Tab», еще живы и вполне активны. К слову, автор этой статьи сам частенько пользуется Tab`ом при заполнении различных форм. И, между прочим, как горячая клавиша, Tab здорово ускоряет работу.

Веб-разработчикам не стоит забывать про наше существование – обязательно тестируйте свои формы на корректный отклик на клавишу Tab. И помните, что кроме того, что такое переключение между формами само по себе должно иметь место, вы также должны позаботиться о достаточном визуальном выделении активных элементов.

Фокусировка при переключении Tab`ом в Firefox и Chrome.

Как правильно ограничивать количество попыток авторизации или восстановления доступа к аккаунту.

Рано или поздно, но множественные попытки авторизации или восстановления пароля следует останавливать. Можно снисходительно отнестись к 5 или даже 10 попыткам, однако их настойчивое продолжение должно вас насторожить. С дальнейшими операциями по аутентификации, регистрации или восстановлению аккаунта вы должны работать.

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

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

Если по истечению этого времени пользователь, взломщик или бот продолжит делать ошибки, то вы вполне можете последовательно увеличивать временной интервал до внушительных значений.
Стоит заметить, что подобные техники с последовательно увеличивающейся временной блокировкой должны быть привязаны к одному IP – не забывайте, что после безуспешных действий злоумышленника, приведших к блокировке, вашим сайтом вполне может воспользоваться настоящий пользователь, IP которого будет, разумеется, другим.

Виды авторизации

Существует несколько моделей авторизации. Три основные — ролевая, избирательная и мандатная.

  • Ролевая модель. Администратор назначает пользователю одну или несколько ролей, а уже им выдает разрешения и привилегии. Эта модель применяется во многих прикладных программах и операционных системах.

    Например, все пользователи с ролью «Кассир» имеют доступ к кассовым операциям в бухгалтерской системе, а пользователи с ролью «Товаровед» — нет, зато у них есть доступ к складским операциям, при этом обе роли имеют доступ к общей ленте новостей.

  • Избирательная модель. Права доступа к конкретному объекту выдают конкретному пользователю. При этом право определять уровень доступа имеет либо владелец конкретного объекта (например, его создатель), либо суперпользователь (по сути, владелец всех объектов в системе). Кроме того, пользователь, обладающий определенным уровнем доступа, может передавать назначенные ему права другим.

    Например, пользователь А, создав текстовый файл, может назначить пользователю Б права на чтение этого файла, а пользователю В — права на его чтение и изменение. При этом пользователи Б и В могут передать свои права пользователю Г.

    Избирательная модель применяется в некоторых операционных системах, например в семействах Windows NT (в том числе в Windows 10) и Unix. По этой же модели предоставляется доступ, скажем, к документам на диске Google.

  • Мандатная модель. Администратор назначает каждому элементу системы определенный уровень конфиденциальности. Пользователи получают уровень доступа, определяющий, с какими объектами они могут работать. Обычно такая модель является иерархической, то есть высокий уровень доступа включает в себя права на работу и со всеми младшими уровнями.

    Мандатная модель авторизации применяется в системах, ориентированных на безопасность, и чаще всего она используется для организации доступа к гостайне и в силовых ведомствах.

    Например, в организации может быть пять уровней доступа. Пользователь, имеющий доступ к файлам 3-го уровня, может также открывать файлы 1-го и 2-го уровня, но не может работать с файлами 4-го и 5-го уровня.

Выбираем правильное хэширование

Идею хранения паролей нашли, то есть хранения не паролей, а их хэшей. А вот какой алгоритм хэширования выбрать?


Давайте посмотрим на то, что пробовали выше – простая функция md5. Алгоритма его расшифровки нет, но тем не менее md5 не рекомендуется для использования. Почему?

Помимо сложности самого алгоритма, есть и другой момент. Да, расшифровать пароль по хэшу нельзя, но его можно подобрать. Простым брутфорсом.
К тому же существуют многочисленные базы паролей md5, где всевозможные варианты хранятся тупо списком.
И подбор вашего пароля по известному хэшу займет столько времени, сколько понадобится для выполнения sql-запроса

    select password from passwords where hash='e10adc3949ba59abbe56e057f20f883e';

Конечно, вы сами не будете использовать пароль 123456, но как насчет ваших пользователей? Да, 123456 можно подобрать и руками, но в таком случае никакие алгоритмы не помогут.
Наша же задача максимально позаботиться о юзерах, которые выбирают пароли сложнее qwerty. Думаем дальше, гуглим.


Помимо md5 есть множество алгоритмов хэширования, sha256, sha512 и еще целая толпа. Их сложность выше, но это не отменяет опять-таки существования таблиц с готовыми паролями.
Нужно что-то хитрее.

Данные и условия задачи

У нас есть полностью закрытый сервер, работающий на

сокетах/вебсокетах

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

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

Заглушка для авторизации

Функции, связанные с авторизацией, будут лежать в отдельном файле и своем пространстве имен. Создадим файл auth.php в api/v1/common – там, где уже лежит helpers.php.
Если вы разбирали уроки админки, особенно третий, про серверную часть, то эти пути вам будут знакомы. Если у вас свой проект, то кладите auth.php куда удобно.
Главное, потом правильно указать пути.

Содержимое auth.php

Как обойтись без шифрования. хэширование

Фокус в том, что не нужно хранить пароли в открытом виде, но и не нужно шифровать их с возможностью расшифровки. Пароли нужно хэшировать и в базе хранить не пароль, а его хэш.
Хитрым образом закодированную строку, которую нельзя расшифровать. Например, не password, а 5f4dcc3b5aa765d61d8327deb882cf99

Вы можете спросить, что это за хрень и как же сравнить пароль, введенный пользователем, с паролем, лежащим в базе. А нам и не нужно сравнивать пароли – достаточно сравнить их хэши.


Например, есть простая функция хэширования md5. Вот так она работает

Насущные проблемы

Люди будут упоминать такие вещи как прокси, динамические IP и другие вещи. Сейчас мы разберем их.

1) Динамические IPКак известно, если IP изменяется, то нарушается соединение с сервером. Оно просто сбрасывается. Нужно снова повторять процедуру авторизации. Вполне реально сделать повторное подключение не заметным для пользователя, реализовав на клиенте повторное подключение и повторно выяснить внешний IP. Так мы будем уверены в том, что клиент сможет без препятствий соединиться с сервером по новой.

2) ПроксиК счастью, прокси никак не смогут нарушить нормальную работу клиента. Если клиент будет пользоваться открытыми проксями, то он подвергает себя опасности перехвата авторизации и будет сам себе злым Буратино.

Хотелось бы, чтоб пользователи хабра добавили сюда еще свои вопросы или проблемы, которые могут возникнуть.

Одноразовый пароль с текущим временем

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

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

Мы убиваем сразу 2х зайцев: рассинхронизацию времени и перехват хэша.

Статья – аутентификация и авторизация в микросервисных приложениях [часть 1]

Доброго времени суток, codeby.

Сегодня хочу рассказать об обеспечение безопасности микросервисного приложения. Тема довольно интересная и поистине творческая: существует довольно большое множество способов, которые меняются от системы к системе. В рамках двух статей я постараюсь дать хорошие теоретические знания вопроса и практическую реализацию одного из рецептов. Я решил разделить материал, так первая статья будет про теорию а вторая будет чисто практической. Статьи сосредоточены на механизме авторизации и аутентификации, поэтому читателю предлагается самостоятельное погружение в тему микросервисов и их архитектуры. Однако небольшие отступления, дабы читатель видел картину целиком, всё таки будут присутствовать.

В качестве приложения для примера – выбраны микросервисы, из моей статьи о docker. Читателю также предлагается ознакомиться с ними самостоятельно. Стоит сказать, что приложение было модифицировано. Фронтенд вынесен в контейнер с ngnix, о чём я также расскажу во второй части, apigetway мы перепишем в рамках второй части.

Как говорилось ранее – читателю предлагается самостоятельно ознакомится в различии микросервисной и монолитной архитектур. В контексте безопасности стоит сказать, что в монолитной системе за безопасность отвечает сам монолит. В противовес, в системе состоящей из микросервисов, чтоб удовлетворить запрос пользователя приходится вовлекать несколько микросервисов, исходя из этого напрашивается вопросы:

  • какие из микросервисов должны отвечать за авторизацию, а какие за аутентификацию
  • предположим, что одни из сервисов аутентифицировал пользователя, значит ли это что этому пользователю должны доверять другие микросервисы
  • должны ли микросервисы доверять другу
  • должны ли все микросервисы иметь доступ ко всем микросервисам, т.е. имеют ли право все микросервисы обращаться друг к другу

Как раз в этом месте и начинается творчество. Проблема заключается в том, что ответы на приведённые вопросы сильно различаются. Нельзя не заметить, что различия коррелируют с особенностью рассматриваемой системы – ответы, которые правильны для системы А будут в корне не верны для системы Б и так далее.

Кейсы аутентификации и авторизации встречается во всех системах. Различие между монолитом и микросервисами (в контексте данных проблем) в том, что в микросервисной системе всегда присутствует вопрос о том, какие из микросервисов должны отвечать за авторизацию и аутентификацию.

Словарь

Рассуждая теоретически, очень важно говорить на одном языке, поэтому давайте для начала определимся с некоторыми моментами.

Задача аутентификации – убедиться, что пользователь – тот за кого себя выдаёт.

Задача авторизации – убедиться, что пользователь имеет право делать то или иное действие в системе.

Данные бывают передаваемыми и хранимыми. Передаваемые данные – это данные которые “гуляют” от микросервиса до микросервиса. Хранимые – это данные которые хранятся в базах данных микросервисов.

Область действия – идентификатор для группы ресурсов, которые необходимо защитить. Например, все конечные точки способные изменить местоположение Пети, должны входить в группу location_information_write. Этакие наименования прав.

Маркер доступа – подписанный объект, используемый для предоставления доступа к микросервисам. Микросервис может запросить маркер доступа к любой области действий, если доступ разрешен – микросервис начинает взаимодействовать с разрешенной зоной.

OAuth и OpenId Connect – мы будем использовать эти протоколы для аутентификации и авторизации, реализацию возьмём из IdentityServer.

Аутентификация

Разобравшись с понятиями давайте приступим к размышлениям. Напомни, что раньше мы использовали архитектуру frontend for backend, где в качестве бэкэнда мы использовали микросервисы. Тогда каждый фрагмент фронтенда либо прорисовывался, либо нет – в зависимости от того был ли запущен сервис. Сейчас же давайте изменим архитектуру на нечто такое:

Что произошло: я вынес фронтенд часть на волю ngnix, действительно, нет особой необходимости иметь целый .net core проект, который существует лишь для того, чтобы рендерить заглавную страницу сайта, ngnix легковесней, дешевле и быстрее, этого вполне достаточно чтобы сделать выбор в его пользу. Появилось бизнесс-требование, которое гласит: “Необходимо дать пользователю возможность предустанавливать свою страну и город, для корректного вывода погоды и курса валют”. Вот у нас и появился функционал, который должен быть разграничен пользовательским контекстом. Так для Пети из Москвы погода и курс рубля к доллару будет отличаться от Тараса из Харькова (курс валюты для Тараса будет представлен как гривна к доллару).

Появился микросервис Login, в рамках которого и строится дальнейшее проектирование, предполагается что микросервис логин будет аутентифицировать пользователей, так как только Петя может менять свои настройки, ну суть ясна я думаю.

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

Тут нам на помощь придёт промежуточное ПО, которое перенаправляет пользователей, которые не вошли в систему, в микросервис Login. Сам же микросервис Login решает как именно пользователь будет входить в систему и проводит его через процесс входа. В рамках статьи, Петя и Тарас смогут попасть в систему двумя способами:

Вне зависимости от способа входа, микросервис Login должен предоставлять подтверждение API Gateway того, что пользователь аутентифицирован, в таком виде в котором API Gateway предоставляет возможность проверить подлинность. Для этого существуют различные протоколы, в данном случае мы будем использовать OpenId Connect.

Хочу обратить ваше внимание, что аутентификация пользователя происходит на периферии системы, т.е. она проводится микросервисом, получившем запрос непосредственно от пользователя (через промежуточное ПО перенаправления). Это хорошо зарекомендовавший себя принцип разработки систем безопасности для микросервисов: аутентификация пользователя происходит на периферии системы.

Авторизация пользователей

После аутентификации пользователя – мы знаем кто он такой, однако в нормальных системах присутствует система прав, а значит знания, что пользователь является тем за кого себя выдаёт не гарантирует того что у пользователя есть разрешение на совершение того или иного действия. Ну банальный пример: уборщице Таси не нужно давать разрешения на визирование документов отправленных Тарасом для Петра. Также понятно, что система должна отклонять запрос на изменение местоположения Тараса направленного от имени Петра.

Так как мы имеем дело с микросервисной архитектурой, нам нужно понять какой сервис должен отвечать за авторизацию запросов. И вот ответ: поскольку один микросервис это всегда одна бизнес-возможность, мы вполне можем оставить авторизацию в конкретном сервисе. То есть, если Тарас имеет право на визирования документов для Петра, проверку этого визирования можно и нужно оставить в микросервисе документов. Так мы приходим к тому, что авторизация – это тоже часть бизнес возможности, если конкретней то это бизнес-правило.

Теперь поразмышляем о том как это реализовать. Несомненно проясняется факт, что мы должны передавать идентифицированную информацию пользоватяля от микросервиса к микросервису. Так сказать прокидывать её. Эту ответственность мы делегируем нашему Api Gateway так как именно он первым принимает запросы от пользователя, он должен каким то образом модифицировать пользовательский запрос.

Доверие микросервисов друг к другу

Поговорим о моменте, который нередко (разумеется во вред) упускается из вида. Смоделируем ситуацию атаки, допустим злоумышленник смог завладеть микросервисом валют и собирается отправить от его имени запрос на изменение логина и пароля Тараса на микросервис Login. В сценарии, где микросервисы доверяют друг другу и ничем не ограничены – мы, как blue team, потерпели сокрушительное фиаско. Однако, если голова нам дана “не чтоб шапку носить” и мы ограничили доступ к микросервису Login (разумно, чтоб его мог вызывать только Api Gateway, так как он находится на периферии) то всё будет хорошо.

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

Чтобы обеспечить ограничение по взаимодействию – мы создадим в микросервисе Login области действий (см словарь). При необходимости вызова другого микросервиса, вызывающий микросервис должен будет запросить доступ у микросервиса Login в виде маркера доступа к конкретной области действия. К тому же мы должны передавать эти данные в зашифрованном виде, а не обычным текстом.

Google OAuth

Напоследок хочу сказать пару слов о том, как работает гугл аутентификация.

Давайте взглянем на картинку:

Процесс описан сверху вниз. В данном случае Client – это фронтенд часть приложения которое мы обсуждаем. Server – это его серверная часть, которая представлена у нас микросервисом Login. Google API Server – апи гугла, с которым мы будем взаимодействовать, а OAuth Dialog – это тот самый диалог, которые предоставляет гугл для аутентификации юзеров. Для использование google oauth нам нужен api-ключ: не имеет смысла расписывать пошагово как его получить, поэтому вот:

Implement social authentication with React RESTful API

Ну а в следующей части я расскажу и покажу как всё это реализовать.

Заключение

В статье предложена универсальная модель для авторизации доступа множеству пользователей к множеству ресурсов с минимальными потерями по производительности, позволяющая делать эффективное кеширование и хранение промежуточных данных на микросервисах, для сборки результата авторизации just-in-time.

Предложена метрика (в виде коэффициента), для оценки работы авторизации микросервисов с учетом требований работы всего комплекса и показано, как он может меняться в зависимости от подхода, а именно наличия/отсутствия кеша, хранения ролей в JWT токене и т.д. Не показано, что этот коэффициент всегда растет с увеличением количества под в системе.

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

Показано, что при малом количестве микросервисов нет смысла проводить кеширование на клиенте авторизации, так как это приведет к большей нагрузке на ЦПУ. Предоставлены данные, которые позволяют сделать вывод, что необходимо балансировать ресурсы в зависимости от размеров системы, если она слишком мала, то есть смысл нагружать больше сеть, но при увеличении и разрастании выгоднее добавить пару ядер в микросервисы, для обеспечения работы кешей и разгрузки сети, микросервисов авторизационных данных.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *