Русский
Русский
English
Статистика
Реклама

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

Перевод Не стоит создавать собственные решения для аутентификации пользователей

19.06.2020 18:10:12 | Автор: admin
Автор статьи, перевод которой мы публикуем, предлагает прекратить писать собственный код для аутентификации пользователей. Он полагает, что пришло время внедрять более безопасные решения, которые, если даже не говорить о других их плюсах, позволяют экономить время и деньги.

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



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

Разработка безопасной системы аутентификации пользователей это по-настоящему сложная задача. Она гораздо масштабнее, чем многие думают. Эту задачу очень легко решить неправильно. Хуже того: ошибки при создании подсистем аутентификации могут повлечь за собой катастрофические последствия. В базовую структуру систем аутентификации и управления пользователями входит всего несколько форм. Из-за этого создание подобных систем может показаться весьма простым делом. Но, как известно, дьявол кроется в деталях. Нужно немало потрудиться для того чтобы сделать такие системы безопасными (и, когда это возможно или даже необходимо, учесть в них требования конфиденциальности персональных данных).

IDaaS


К счастью, у современного веб-разработчика нет необходимости в развёртывании собственной системы для аутентификации пользователей и для управления ими. Сейчас, в 2020 году, существует множество хороших IDaaS-решений (Identity as a Service, идентификация как сервис). Применение таких решения значительно упрощает оснащение веб-проектов возможностями по аутентификации пользователей.

Вот несколько популярных IDaaS-проектов (в алфавитном порядке): Auth0, Azure AD, Google Identity Platform и Okta.

Кроме того, существуют поставщики идентификационной информации, основанной на чём-то наподобие учётных записей пользователей социальных сетей. Это, например, Apple, Facebook, GitHub, Twitter. Разработчикам очень легко внедрять в свои проекты возможности этих систем. Тот, кто работает с провайдерами аутентификации, может очень быстро создать соответствующую подсистему приложения, имеющую доступ к большому массиву данных о пользователях. Но иногда взаимодействие проекта с провайдерами может иметь негативное влияние на конфиденциальность данных пользователей.

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

Чем больше пользователей тем безопаснее решение


Большинство поставщиков идентификационной информации предлагаю дополнительные возможности, касающиеся безопасности. Такие, как поддержка многофакторной аутентификации (MFA, multi-factor authentication), поддержка сертификатов безопасности или ключей (в том числе U2F, FIDO2, WebAuthn и прочее подобное).

Не стоит недооценивать важность этих технологий. В соответствии с отчётом Microsoft, включение MFA позволяет предотвратить до 99,9% атак на учётные записи.

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

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

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

Распространённые возражения, высказываемые об использовании сторонних сервисов аутентификации


На самом деле, не так уж и сложно создать собственную систему для аутентификации пользователей и для управления ими


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

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

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

То, что правильное управление паролями, это непростая задача, не должно никого удивлять. А вы знали о том, что управление именами пользователей это тоже сложно? Например, тот факт, что имена пользователей выглядят одинаково, ещё не означает, что система, при их сравнении, сочтёт их таковыми. В этом выступлении 2018 года высказаны ещё некоторые интересные идеи, касательно того, что может пойти не так при работе с такими простыми сущностями, как имена пользователей.

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

Использование сервисов аутентификации пользователей не всегда бесплатно, особенно для крупных проектов


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

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

Я очень опытный разработчик, поэтому знаю о том, как создать безопасную систему аутентификации


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

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

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

Я хочу держать под контролем пользователей моего проекта


Я, рассматривая данную идею, сразу хочу задать вам вопрос: А зачем вам это?. Вполне возможно то, что вам это по-настоящему не нужно. Ну, если только вы не разрабатываете новый Facebook. В таком случае данные о пользователях это ваш самый главный актив, и чем больше таких данных вы соберёте, тем лучше.

Кроме того, чем больше данных о пользователях вы собираете тем выше вероятность того, что вам придётся потратиться на то, чтобы привести свою систему в соответствие с некими правилами, вроде GDPR. Далее, если вы храните большие объёмы данных о пользователях, это может утяжелить последствия взломов и потребовать дополнительных расходов на устранения этих последствий.

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

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

С чего начать?


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

Для начала хорошая новость. Она заключается в том, что все четыре вышеперечисленных провайдера (Auth0, Azure AD, Google Identity Platform, Okta), да и многие другие, используют одни и те же протоколы: OpenID Connect / OAuth 2.0. Это современные стандартные протоколы, клиентские библиотеки для поддержки которых существуют практически для всех языков программирования и фреймворков.

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

  1. Зарегистрируйте приложение у поставщика идентификационной информации. Вам, после регистрации, выдадут идентификатор (Application ID, Client ID) и секретный ключ (Secret Key, Client Secret).
  2. Задайте разрешения, необходимые вашему приложению. В дополнение к тому, что приложению будет доступен профиль пользователя, вы, что зависит от выбранного провайдера, сможете получить доступ к гораздо большему объёму данных. Сюда может входить, например, доступ к сообщениям пользователей и доступ к их облачному хранилищу (например через Office 365 или G Suite).
  3. Интегрируйте клиентскую библиотеку сервиса аутентификации в свой проект.

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

  1. Приложение перенаправляет пользователя на страницу провайдера аутентификации.
  2. Пользователь аутентифицируется и перенаправляется на страницу вашего приложения.
  3. Приложение получает JWT-токен.

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

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

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

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

Использование OpenID Connect в клиент-серверных приложениях


То, как именно в конкретном приложении будет использоваться механизм OpenID Connect, сильно зависит от того, с использованием какого языка и фреймворка создано приложение.

На сайте jwt.io можно найти исчерпывающий список библиотек, которые можно использовать для верификации JWT-токенов.

Для некоторых стеков технологий, кроме того, можно воспользоваться решениями более высокого уровня. Например это, в среде Node.js/Express, express-jwt или passport.

Использование OpenID Connect на статических сайтах или в нативных приложениях


Статические веб-приложения (их ещё называют JAMstack-сайтами) и нативные приложения (то есть настольные или мобильные приложения) тоже могут пользоваться OpenID Connect, но делается это немного не так, как в случае с обычными веб-проектами. В спецификации OAuth 2.0 это называется implicit flow, или получение токена доступа напрямую от пользователя.

При таком подходе не нужно использовать механизм, в котором применяется секретный ключ (Client Secret). Дело в том, что приложение выполняется на клиенте, поэтому не существует безопасного способа распространения подобных ключей. Здесь применяется следующая последовательность действий:

  1. Приложение перенаправляет пользователя на аутентификационную конечную точку, проверяя, чтобы строка запроса содержала бы scope=id_token.
  2. Пользователь выполняет аутентификацию, пользуясь возможностями поставщика идентификационной информации.
  3. Пользователя перенаправляют к приложению, JWT-токен сессии прикрепляется к URL страницы в виде URL-фрагмента (URL-фрагмент это то, что следует за знаком #). Он находится в поле, называемом id_token.
  4. Приложение получает JWT-токен из URL-фрагмента и проверяет его. Если токен успешно проходит проверку, пользователь считается аутентифицированным, а это значит, что приложение может использовать сведения о пользователе из токена.

Для того чтобы проверить JWT-токен в статическом веб-приложении можно использовать модуль idtoken-verifier. Настольные и мобильные приложения могут использовать похожие библиотеки. Конкретная библиотека зависит от технологии, использованной при разработке приложения.

При разработке клиент-серверных проектов, таких, как статические веб-ресурсы или нативные приложения, важно обеспечить то, чтобы токен был бы подписан с использованием RSA-SHA256 (в заголовке токена alg должно быть записано RS256). Речь идёт об использовании механизма асимметричного шифрования: поставщик идентификационной информации подписывает токены с использованием секретного ключа, а приложение может проверить токен с использованием публичного ключа. Ещё один распространённый алгоритм, применяемый для подписи токенов, это HMAC-SHA256 (или HS256). Тут используется симметричное шифрование, для подписи и проверки токенов применяется один и тот же ключ. Проблема тут в том, что нельзя организовать безопасное хранение подобных ключей в клиентских приложениях.

Затем клиентское приложение может использовать полученный и проверенный JWT-токен в запросах, выполняемых к серверным API. Обычно токены передают либо в заголовке Authorization, либо используя куки-файлы. В данном случае JWT функционирует как любой другой токен сессии, но он, при этом, ещё и содержит сведения о пользователе.

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

Какие механизмы аутентификации пользователей применяете вы?



Подробнее..

Аутенти(фи?)кация

22.08.2020 02:17:10 | Автор: admin
Некоторые термины, заимствуемые из английского, входят в русский язык с нарушением всех языковых правил. Характерный пример из 90-х слово флуд, непохожее ни на транскрипцию [fld], ни на транслитерацию flood. Более свежий пример биткоин: окончание -оин характерно для химических веществ (героин, бензоин и т.д.), и читается совсем не так, как английское bitcoin; но там хотя бы можно оправдать русское написание транслитерацией.

Теперь я всё чаще, и в т.ч. на хабре, встречаю слово аутентификация в качестве кальки английского authentication. Английское слово образовано от латинского authenticatus и далее от греческого ни в одном из них нет -фи-, -fi- или --! Более того, братья-славяне пишут автентикация по-болгарски и аутентикациа по-сербски.

Слово аутентикация когда-то и по-русски писалось без -фи-. Гугл находит примеры из книг 1927, 1964 и 2002 г.г.:







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

Тем не менее, аутентификация появилась задолго до компьютеров гугл находит её в книгах 1959, 1962 и 1964 г.г.:





Таким образом, в середине прошлого века аутентикация и аутентификация сосуществовали на равных; но в 2004 в обсуждении в fido7.ru.spelling уже пишут, что аутентификация единственный устоявшийся вариант, и вероятно, -фи- перешло по аналогии из идентификации операции, близкой и по смыслу, и по этимологии: значит сам, dem тот же самый; а идентификация субъекта примерно совпадает с его аутенти(фи)кацией. Статья Технический ликбез (2011) ещё более категорична: Интересно, что в английском языке, откуда позаимствовано это слово, нет слога фи: authentication буквально установление аутентичности, подлинности. Вероятно, поэтому некоторые и пишут аутентикация, хотя такое слово словарями не зафиксировано. В действительности же орфографические словари до сих пор включают оба варианта, хотя
аутентикация встречается всё реже и реже.

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

Смарт-карт ридер JCR721 обзор возможностей и особенностей

16.10.2020 12:13:24 | Автор: admin

Сегодня предлагаем к рассмотрению новую модель смарт-карт ридера JCR721 производства"Аладдин Р.Д.".JCR721 профессиональный отечественный доверенный смарт-карт ридер для работы со смарт-картами в корпоративной среде, имеет привычный вид дляEnterprise-сегмента.

Немного о полезных свойствах и корпусе

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

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

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

В случае с карт-ридеромJCR721 контактная площадка остаётся невредимой даже после 10 тысяч подключений.

Так выглядит карта и контактная площадкапосле 1 000подключений на обычном ридере со скользящими контактами

Так выглядит карта и контактная площадкапосле 10 000подключений на ридере JCR721 с механизмом микролифтTM

Отметим, что ресурс карт-ридераJCR721 не менее 200 000 подключений смарт-карт (вместо50000).

Внешний вид и подключение

Смарт-карт ридерJCR721 имеет пластиковый корпус, шнур для подключения к персональному компьютеру. Разъём шнура для подключения стандартныйUSB2.0Type-A. Для корректной работы на ПК требуется хотя бы один свободный порт USB 2.0 Full-speed (12 Мбит/с), ридер также может работать с USB 1.1, 2.0, 3.0, 3.1. Необходимо обеспечить подачу электропитания 5В 0.25В при токе 300 мА, которое должно обеспечиваться исправным USB-портом (USB 2.0). Для стабильной работы требуется подключение к ПК, не используя дополнительные переходники, можно использоватьUSB-хабы с внешним источником питания, но еслиUSB-хаб не имеет внешнего источника, то этого может быть недостаточно для работы ридера, т.к. сам по себеUSB-хаб обеспечивает менее 100мАна порт.

Также ридерJCR721 имеет и шнур для подключения к современным ноутбукам и портативным устройствам, имеющим разъемUSB3.1Type-C.

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

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

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

Можно отметить, учитывая все эти параметры, что ридер предназначен для интенсивного использования с любыми типами контактных микропроцессорных смарт-карт. Поддерживает работу с любыми контактными смарт-картами (MCU) стандарта ГОСТ Р ИСО/МЭК 7816-3-2013 Class A, B, C (5V, 3V, 1.8V) по протоколам Т=0/Т=1. Может использоваться в системах ГИС, АСУ ТП, для обеспечения безопасности персональных данных 1-го уровня защищённости, на предприятиях КИИ (критической информационной инфраструктуры), в госорганах, на предприятиях ОПК, Министерства Обороны, в банках, многофункциональных центрах (МФЦ), офисах обслуживания, в проектах типа "Электронное удостоверение", "Электронное правительство", "Электронное декларирование" и многих других.

Компания "Аладдин Р.Д." заявляет, что ридер является доверенным средством работы с данными пользователя, которые хранятся или будут храниться на смарт-картах. Ридер спроектирован по новым Требованиям доверия ФСТЭК России, в том числе для работы с гостайной.

Если рассматривать ридер для поддержки Memory-карт, работавшими по протоколам I2C (S=8), 3-wire(S=9), 2-wire(S=10), картами-счётчиками, ранее применявшимися в "телефонных картах", то на данном этапе этой поддержки нет.

Ещё немного о преимуществах нового смарт-карт ридера JCR721

Ридер очень быстрый, поддерживает все современные смарт-карты, реальная подтверждённая скорость обмена данными со смарт-картой до 625 Кбит/с. Быстродействие ридеров при работе со смарт-картой зависит от нескольких факторов. Фактор 1 скорость обмена с хостом (ПК) по интерфейсу USB 2.0., а также фактор 2 тактовая частота, подаваемая ридером на смарт-карту.

В большинстве ридеров эта частота, фиксированная (как правило, 4 МГц). Некоторые ридеры могут подавать различные частоты из фиксированного перечня (указывается в функциональном дескрипторе CCID-устройства). Смарт-карт, работающих на частоте выше 5 МГц, практически нет, поэтому чем выше частота, подаваемая ридером на смарт-карту, тем больше шансов, что данный ридер будет несовместим с большинством имеющихся на рынке смарт-карт. Стоит различать скорость обмена данными со смарт-картой и скорость при работе со смарт-картой. Последняя складывается из времени отправки команды на смарт-карту, времени обработки команды смарт-картой и времени передачи ответа от смарт-карты на ПК.

Работает смарт-карт ридер JCR721 со всеми современными операционными системами, включая Linux (со всеми российскими дистрибутивами), macOS, ОС "Эльбрус", МС ВС, Android, Sailfish/Аврора, на процессорах IA-32, IA-64, x86-64, ARM, Эльбрус, Байкал и на Microsoft Windows. Также ридер может быть подключен к ПК, где используются средства виртуализации, такие, как Hyper-V, Citrix XenServer, Virtual Box, VMWare и др.

Для работы ридера JCR721 не требуется установки специального прикладного ПО, работа ведётся через стандартные программные интерфейсы PC/SC, является CCID-совместимым устройством, не требует установки специальных драйверов и работает сразу при подключении к USB-порту компьютера (Plug and Play).

Нужно отметить, что в современных версиях ОС Windows, Linux, macOS, МС ВС, "Эльбрус", Android8 (Oreo), Sailfish Mobile при подключении ридер в системе должен определиться автоматически, при этом на его корпусе должен загореться зелёный индикатор. В этих операционных системах для работы уже существует предустановленный CCID-драйвер и входит в состав данных операционных систем. А вот для работы с операционными системами версий Microsoft Windows XP SP3 CCID-драйвер может быть установлен администратором из "Каталога Центра обновления" Microsoft при первом подключении к рабочей станции. Также для архитектуры X86, CCID-драйвер можно скачать по ссылке:http://catalog.update.microsoft.com/v7/site/ScopedViewRedirect.aspx?updateid=8e217a56-9ed7-456b-aee8-674c5c7bcdbe

Актуальный список поддерживаемых ОС, гипервизоров, виртуальных сред и процессоров можно узнать на продуктовой странице сайта Производителя https://www.aladdin-rd.ru/catalog/readers/JCR-721

Но вот если ридер автоматически не определился в системе, то одной из возможных причин может быть использование устаревших версий ОС или версий Firmware ("прошивок") терминального оборудования. Для устранения проблемы следует прописать указанные VID/PID в Info.plis и/или обратиться с этой проблемой к производителю ОС или терминального оборудования.

Идентификатор класса устройств USB: 0x0B

VID (Vendor ID): 0х24DC

PID (Product ID): 0х0428

Для Astra Linux 1.4, Astra Linux 1.5 и МС ВС 3.0 подсистема поддержки работы со смарт-картами PC/SC и CCID-драйвер перед первым использованием ридера должны быть установлены на рабочую станцию администратором, согласно инструкциям для определённого типа операционных систем. Работа ридера в этих ОС "из коробки" не гарантируется.

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

Итак, производитель заявляет следующий ряд характеристик:

- Климатическое исполнениеустройства: группа 1.1 УХЛ-4

- Температура эксплуатации: +2510С

- Относительная влажность воздуха: от 40% до 60%

- Атмосферное давление: 96 кПа - 103 кПа (720 - 770 мм рт. ст.)

Предельными условиями эксплуатацииявляются параметры:

- Температура: от 0С до +70С, при температуре воздуха выше +30С влажность не должна превышать 70%

- Относительная влажность воздуха: до 80%, без конденсата

- Атмосферное давление: 84 кПа - 106,7 кПа (630 - 800 мм рт. ст.)

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

Ридер безопасен для здоровья человекаи соответствует требованиям Единых санитарно-эпидемиологических и гигиенических требований к товарам, подлежащим санитарно-эпидемиологическому надзору. Сертификат соответствия можно найти на сайте производителя во вкладке "Доп. ресурсы"https://www.aladdin-rd.ru/catalog/readers/JCR-721.

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

Небольшое сравнение ридера JCR721 с ближайшими аналогами

Для сравнения мы выбрали несколько параметров: качество контактной группы и её ресурс, поддержка типов смарт-карт, безопасность и доверие.

Качество контактной группы, её ресурс:

Поддержка различных типов карт:

Безопасность и доверие:

Немаловажно отметить, что цена для ридера адекватна для больших проектов.

Модель

Разработчик-производитель

Страна производства

Цена

Ридеры в горизонтальном исполнении

1

JCR721

Аладдин

Россия

1,399

2

ASEDrive IIIe v2

NXP (Athena)

Тайвань

2,750

3

ASEDrive IIIe v3 Mini

NXP (Athena)

Тайвань

Россия

2,200

4

Rockey 301 C11

Feitian

Китай

1,480

5

OMNIKEY (CardMan) 3021

HID

США

1,546

6

IDBridge CT30

Gemalto

Китай

1,250

Цена взята с сайта рассматриваемых поставщиков в России посостоянию на 14 октября 2020 г.

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

Подробнее..

Токен Авторизации

20.12.2020 22:09:52 | Автор: admin

В настоящее время киберпреступность стала проблемой мирового уровня. Например, Дмитрий Самарцев, директор BI.ZONE в сфере кибербезопасности привёл на Всемирном экономическом форуме следующие цифры. В 2018 году ущерб мировой экономики от киберпреступности составил по его словам 1.5 триллиона долларов. В 2022 году прогнозируются потери уже в 8 триллионов, а в 2030 ущерб от киберпреступлений может превысить 90 триллионов долларов. Чтобы уменьшить потери от киберпреступлений, необходимо совершенствовать методы обеспечения безопасности пользователей. В настоящее время существует множество методов аутентификации и авторизации, которые помогают реализовать надежную стратегию безопасности. Среди них многие эксперты выделяют в качестве лучшей авторизацию на основе токенов.

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

Рассмотрим эту систему. Как правило, идеология их применения базируется на следующих принципах:

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

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

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

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

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

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

Типы токенов авторизации

Токены авторизации различаются по типам. Рассмотрим их:

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

  2. Устройства, которые находятся достаточно близко к серверу, чтобы установить с ним соединение, но оно не подключаются физически. Примером такого типа токенов может служить "magic ring" от компании Microsoft.

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

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

Процесс токен авторизации

Авторизация с помощью токена происходит следующим образом. Сначала человек запрашивает доступ к серверу или защищенному ресурсу. Запрос обычно включает в себя ввод логина и пароля. Затем сервер определяет, может ли пользователь получить доступ. После этого сервер взаимодействует с устройством: ключ, телефон, USB или что-то ещё. После проверки сервер выдает токен и отправляет пользователю. Токен находится в браузере, пока работа продолжается. Если пользователь попытается посетить другую часть сервера, токен опять связывается с ним. Доступ предоставляется или, наоборот, запрещается на основе выданного токена.

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

Что такое аутентификация на основе токенов?

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

  1. аутентификация по паролю (обычное запоминание комбинации символов)

  2. аутентификация по биометрии (отпечаток пальца, сканирование сетчатки глаза, FaceID)

  3. аутентификация токенов

Аутентификация токенов требует, чтобы пользователи получили сгенерированный компьютером код (или токен), прежде чем им будет предоставлен доступ в сеть. Аутентификация токенов обычно используется в сочетании с аутентификацией паролей для дополнительного уровня безопасности (двухфакторная аутентификация (2FA)). Если злоумышленник успешно реализует атаку грубой силы, чтобы получить пароль, ему придется обойти также уровень аутентификации токенов. Без доступа к токену получить доступ к сети становится труднее. Этот дополнительный уровень отпугивает злоумышленников и может спасти сети от потенциально катастрофических нарушений.

Как токены работают?

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

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

Хотя эти традиционные системы аутентификации токенов все еще действуют сегодня, увеличение количества смартфонов сделал аутентификацию на основе токенов проще, чем когда-либо. Смартфоны теперь могут быть дополнены, чтобы служить генераторами кодов, предоставляя конечным пользователям коды безопасности, необходимые для получения доступа к их сети в любой момент времени. В процессе входа в систему пользователи получают криптографически безопасный одноразовый код доступа, который ограничен по времени 30 или 60 секундами, в зависимости от настроек на стороне сервера. Эти мягкие токены генерируются либо приложением-аутентификатором на устройстве, либо отправляются по запросу через SMS.

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

Безопасно ли использование токенов?

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

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

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

Рекомендации по аутентификации на основе токенов

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

  1. Правильный веб-токен. Хотя существует целый ряд веб-токенов, ни один из них не может обеспечить ту же надежность, которую предоставляет веб-токен JSON (JWT). JWT считается открытым стандартом (RFC 7519) для передачи конфиденциальной информации между несколькими сторонами. Обмен информацией осуществляется цифровой подписью с использованием алгоритма или сопряжения открытого и закрытого ключей для обеспечения оптимальной безопасности.

  2. Приватность.

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

Что такое JSON веб-токены?

JSON Web Token (JWT) - это открытый стандарт (RFC 7519), который определяет компактный и автономный способ безопасной передачи информации между сторонами в виде объекта JSON. Эта информация может быть подтверждена благодаря цифровой подписи. JWT может быть подписан с помощью секрета (с помощью алгоритма HMAC) или иным образом, например, по схемам RSA или ECDSA.

В своей компактной форме веб-токены JSON состоят из трех частей, разделенных точками: заголовок, полезная нагрузка, подпись. Поэтому JWT выглядит обычно выглядит следующим образом: xxxx.yyyy.zzzz.

Заголовок состоит из двух частей: типа токена, которым является JWT, и используемого алгоритма подписи, такого как HMAC SHA256 или RSA.

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

Зарегистрированная - это набор ключей, который не является обязательными, но рекомендуются для обеспечения улучшения безопасности. Например, iss - уникальный идентификатор стороны, генерирующей токен, exp - время в формате Unix Time, определяющее момент, когда токен станет не валидным, и другие.

Публичная информация может быть определена по желанию теми, кто использует JWT. Но они должны быть определены в реестре веб-токенов IANA JSON или определены как URI, который содержит устойчивое к коллизиям пространство имен. Частная - это пользовательская информация, созданная для обмена данными между сторонами, которые согласны их использовать. Получим вторую часть с помощью кодирования Base64Url.

Тоже не понял, что за прикол там происходит.

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

Выходные данные представляют собой три строки Base64-URL, разделенные точками, которые могут быть легко переданы в средах HTML и HTTP, будучи при этом более компактными по сравнению со стандартами на основе XML, такими как SAML.

Пример:

eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NSIsIm5hbWUiOiJKb2huIEdvbGQiLCJhZG1pbiI6dHJ1ZX0K.LIHjWCBORSWMEibq-tnT8ue_deUqZx1K0XxCOXZRrBI

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

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

Почему стоит использовать токены авторизации?

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

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

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

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

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

Подробнее..

Спасибо, что живой как мы выбирали пассивный лайвнесс

29.12.2020 12:11:44 | Автор: admin

Всем привет! Меня зовут Наталья Бессонова, я директор проектов блока цифровой идентичности Ростелеком. В этой статье хочу рассказать о том, как мы выбирали пассивный лайвнесс по одному изображению лица для Единой биометрической системы.

На Хабре не так много статей, посвященных лайвнесс в биометрических системах, а те, что есть, описывают методы и алгоритмы определения лайвнесс или, проще говоря, принадлежности биометрических образцов живому человеку. Отдадим должное их авторам статьи интересные и содержательные, но что если нас интересует насколько хорошо они работают на данных, не входящих ни в один из открытых дата-сетов? Как понять, насколько лайвнесс действительно плох или хорош и какой следует выбирать при необходимости? В этой статье я опишу подход к выбору пассивного singleshot-лайвнесс (т.е. по одному изображению) лица для Единой биометрической системы.

Зачем нужен лайвнесс

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

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

Удалённая банковская идентификация: от сложного к простому, или Банки, зачем вам биометрия?

Мнение автора основано на устаревшей информации. Конкурс Deepfake Detection Challenge по распознаванию дипфейков на видео действительно существует, он проводится компаниями Amazon, Facebook и Microsoft. В этом году отечественная компания NtechLab заняла третье место среди более 2,2 тысячи команд со всего мира.

После прочтения данной статьи только укрепился в мысли, что во всех этих конструкциях есть один лишний элемент сама биометрия. Всё тоже самое точно так же работает и с традиционными способами аутентификации. С той лишь разницей, что вы скорее всего даже не заметите как вашу биометрию заснимут с расстояния 5-10-20 метров. Или вообще восстановят по публичным материалам. Как это уже проделывали. И не раз. И все эти ухищрения, как в этой статье просто упражнения для ума математиков. Но с точки зрения реальной безопасносьи яйца выеденого не стоит.

Ну и да. Уж что-что а социальная инженерия с биометрией упростится просто в разы. Про пин код с карты ещё хоть как-то можно объяснить, что никому не показывать, а вот биометрия Ну откуда бабульки (или даже мне) знать для каких целей меня сейчас снимают: чтобы подтвердить мою личность или чтобы украсть?

Как защитить биометрические данные пользователей от криминального использования

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

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

Новый метод биометрии: биоакустическая подпись

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

Биометрия по лицу, работающая с обычной веб-камеры крайне ненадежна и легко обманывается фоткой. Нормальные лицевые биометрии включают в себя дополнительные средства определения фейков: ИК, 3D и так далее.

Как Сбербанк собирает согласие на обработку биометрии

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

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

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

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

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

Делай по ГОСТу

В июле 2020 года в России введена в действие серия стандартов 58624, устанавливающая термины, классификацию и детальное описание атак на биометрическое предъявление для последующего определения эксплуатационных характеристик. До этого времени не было стандартного руководства для объективной и сопоставимой оценки лайвнесс. Стандарты описывают испытания, объектом которых могут являться:

  • подсистема лайвнесс;

  • подсистема сбора биометрических данных;

  • биометрическая система полностью (контроль качества, распознавание и лайвнесс).

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

  • вероятность ошибки классификации предъявления при атаке вычисляют как долю атак, ошибочно классифицируемых как живые люди;

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

  • вероятность отсутствия ответа на подлинное биометрическое предъявление вычисляют как долю подлинных предъявлений, на которую лайвнесс не ответил;

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

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

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

У нас был сервер, пять веб-камер, один смартфон и пять сотен фотографий

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

В соответствии с требованиями FIDO Biometrics существует три уровня атак, различающихся главным образом усилиями, необходимыми для создания инструмента атаки. Уровень А включает в себя простые распечатки фотографий или фотографии, представленные на дисплее, в то время как уровень В дополнительно включает бумажные маски или видео человека. Уровень С представляет собой силиконовые маски или высококачественные видеозаписи человека, представленные, например, на дисплее с высоким разрешением.

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

  • фотографию лица предъявление распечатанной на цветном принтере фотографии высокого разрешения;

  • 2D-маску предъявление распечатанной на цветном принтере фотографии высокого разрешения с обрезанным фоном;

  • модифицированную фотографию лица предъявление распечатанной на цветном принтере фотографии высокого разрешения с вырезанными отверстиями под рот, нос, глаза;

  • изображение лица на дисплее предъявление выводимой на дисплее фотографии;

  • 3D-маску предъявление силиконовой маски или маски, распечатанной на 3D-принтере.

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

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

Полученная база данных состоит из не менее 300 образцов на каждый инструмент атаки (за исключением силиконовых масок), что дает минимальную достоверную вероятность 1%. Для сбора образцов использовались несколько веб-камер и мобильный телефон:

  • Logitech C270;

  • Logitech C930;

  • Logitech B920;

  • Logitech Brio;

  • Intel Realsense D415;

  • Xiaomi Redmi6.

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

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

Спецификация сервера, на котором проходили испытания:

1) CPU - Intel(R) Core(TM) i5-6600 CPU (4 ядра, 3.30 ГГц, AVX и AVX2 поддерживаются);
2) GPU - Nvidia GeForce GTX 1070 (8 ГБ видеопамяти);
3) ОЗУ - 16 ГБ DDR4;
4) ПЗУ - SSD накопитель SAMSUNG 970 EVO 500ГБ.

Результаты

Я провела испытания 12 методов лайвнесс от независимых вендоров. Все методы, кроме одного, являются пассивными singleshot-методами, для их работы на вход API подаётся RGB изображение лица, на выходе получается liveness score, отражающий насколько предъявленное изображение похоже на подлинное предъявление лица. Один из методов основан на применении 3D-камеры Intel RealSense D415 и, соответственно, на вход принимает RGB изображение и карту глубины изображаемой сцены, а на выходе отдаёт всё тот же liveness score. В таблице ниже приведен перечень измеренных значений эксплуатационных характеристик каждого из протестированных методов лайвнесс.

Рисунок 1 кривые компромиссного определения ошибки при предъявлении атак всех типов (print + replay + mask)Рисунок 1 кривые компромиссного определения ошибки при предъявлении атак всех типов (print + replay + mask)

Алгоритм

ВОКПБП@0.01

ДОПОПБП, мс

СКО_ДОПОПБП, мс

ВООПБП

ДОПОПА, мс

СКО_ДОПОПА, мс

ВООПА

vendor1_v1

0.013

266.501

160.091

0.395

542.772

471.081

0.320

vendor1_v2

0.042

155.626

108.508

0.395

381.548

367.438

0.320

vendor2_v2_CPU

0.048

874.527

21.748

0.008

910.202

60.381

0.039

vendor2_v2_GPU

0.057

863.651

26.629

0.006

903.743

62.957

0.037

vendor1_v3

0.094

110.198

100.997

0.811

293.092

242.255

0.437

vendor3

0.153

146.217

82.217

0.012

360.056

324.149

0.016

vendor2_v1

0.255

874.294

35.319

0.002

1060.088

121.127

0.036

vendor4

0.423

444.085

35.818

0.006

512.427

106.987

0.010

vendor5_v3

0.442

160.426

298.351

0.014

683.258

882.690

0.025

vendor6

0.477

73.560

111.626

0.035

433.866

527.738

0.044

vendor5_v2

0.584

165.370

310.281

0.014

720.696

891.637

0.025

vendor5_v1

0.586

200.883

373.670

0.014

767.726

997.728

0.025

3D liveness

0.777

не измерялось

не измерялось

не измерялось

не измерялось

не измерялось

не измерялось

vendor7

0.967

3021.262

46.769

0.006

3105.798

165.991

0.007

vendor8

1.000

754.956

155.772

0.002

1618.374

1789.670

0.006

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

Также интересно взглянуть на распределение ошибок по инструментам атаки для лучшего решения. Как видно на следующем рисунке, большая часть кривых выглядит как ступенька. Это связано с тем, что метод справился с классификацией с минимальной достоверно измеряемой ошибкой. Например, для случая с силиконовыми масками, где в нашем тесте было минимальное количество образцов атаки, оценка ВОКПА составила 9% и сказать, что действительное значение ВОКПА меньше, мы не можем, для уточнения её значения требуется больше примеров.

Рисунок 2 кривые компромиссного определения ошибки при использовании разных инструментов атак для лучшего методаРисунок 2 кривые компромиссного определения ошибки при использовании разных инструментов атак для лучшего метода

Что делать дальше

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

  • увеличить количество образцов для каждого вида атаки;

  • собрать базы данных для оценки методов лайвнесс для конкретных приложений или продуктов;

  • собрать базы данных для оценки конкретных методов лайвнесс.

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

Буду рада ответить на вопросы в комментариях, если они у вас есть.

Подробнее..

GlobalSign выпустила первый в мире кроссплатформенный агент для управления сертификатами под Windows, macOS и Linux

28.01.2021 02:19:40 | Автор: admin


19 января 2021 года компания GlobalSign объявила о выходе AEG 6.4 новой версии шлюза автоматической регистрации Auto Enrollment Gateway, вместе с которым представлена маленькая, но уникальная программка: кроссплатформенный агент для автоматической выдачи и управления сертификатами под Windows, Mac OS и Linux. Компания заявляет, что это первое такое предложение от любого удостоверяющего центра в мире.

Агент регистрации


Кроссплатформенный агент регистрации небольшая программа, которая устанавливается на устройстве и использует протокол ACME или SCEP для связи с AEG. Во многих случаях агент также обеспечивает соблюдение определённых отраслевых правил или национальных нормативных актов. Кроме того, агент устраняет барьеры для S/MIME, поскольку работает на любой платформе и операционной системе, что также повышает масштабируемость. Например, если из компании увольняется сотрудник, то его ключи автоматически архивируются.

Агент регистрации легко устанавливается на любом клиенте или сервере Windows, macOS и Linux. Утилита помогает устанавливать политики управления сертификатами и управлять с помощью интуитивно понятной панели мониторинга AEG.



Кроме того, агент автоматически выдаёт и контролирует сертификаты. Это великолепно масштабируемый метод развёртывания сертификатов на устройствах, машинах, клиентах S/MIME и серверах организации.

Установка агентов на своих конечных точках даёт организации больший охват и контроль над всей своей сетью, говорит Лила Ки, генеральный директор отдела операций в Северной и Южной Америке GlobalSign. Это также означает, что пользователям и администраторам больше не нужно полагаться на сложные методы регистрации сертификатов, что в конечном итоге улучшает управление сертификатами. Мы действительно ставим последнюю точку в автоматизации этого процесса. AEG 6.4 идеально подходит для организаций, которые хотят начать или оптимизировать удалённую работу, обеспечить безопасность сетей BYOD и автоматизировать функции PKI, которые потребляют время и ресурсы в ручном управлении.

Что такое Auto Enrollment Gateway


Auto Enrollment Gateway это полностью автоматизированное PKI-решение, которое интегрирует PKI непосредственно с Active Directory, поэтому в среде Windows можно автоматизировать выпуск сертификатов и управление ими без необходимости поддерживать собственный удостоверяющий центр. Поддержка протоколов SCEP и ACME v2 расширяет использование сертификатов за пределы домена Windows, позволяя автоматизировать сертификацию для серверов Linux, а также мобильных, сетевых и других устройств.



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

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

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

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

  • Вход в систему с помощью смарт-карт
  • Электронные подписи в документах Microsoft Office,
  • Подпись кода
  • Защита электронных сообщений
  • SSL/TLS
  • Система шифрования данных Encrypted File System (EFS) на уровне файлов в операционных системах
  • Аутентификация пользователей
  • Аутентификация устройств
  • Мобильная аутентификация
  • и т.д.

Шлюз AEG идеально подходит для любой компании с более чем 500 сотрудниками и/или устройствами, а также для тех, кто использует Microsoft Active Directory. Управление PKI и автоматизация особенно востребованы в нынешних условиях, которые требуют от сотрудников удалённой работы.

AEG 6.4 также реализует опции безопасности, в которых сейчас нуждаются компании: S/MIME для безопасной электронной почты, удалённая сетевая аутентификация и инструменты для управления всем этим. Это снижает нагрузку на IT-отдел, экономит время и деньги ресурсов, а также значительно повышает уровень безопасности компании.
Подробнее..

Перевод Пароль как крестраж ещё один способ защитить свои учётные данные

12.02.2021 10:14:08 | Автор: admin

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

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

Правила интернет-безопасности

  1. Длинный пароль лучше короткого. Если длина пароля составляет 16 символов, его почти невозможно подобрать. => cutesamantha15101995 > cutesamantha

  2. Случайные пароли лучше, чем пароли, позволяющие идентифицировать владельца пароля.=> process-cancel-stingy-garnet > cutesamantha15101995

Примечание: технически кодовая фраза process-cancel-stingy-garnet отлично может использоваться в качестве пароля. Она длинная и легко запоминается. В отличие от, скажем, B6fSpxMj&f6DU@5^k длинного сложного пароля из случайных символов.

3. Иметь принципиально разные пароли для разных учётных записей.

Один и тот же пароль для разных учётных записей это всё равно, что один и тот же ключ для разных замков. Ведь вся суть нескольких замков в том, что они _разные_! Кроме того, если использовать несколько паролей, отличающихся одним словом, которое легко угадать (например, ниже), то вы сильно рискуете. Пароли должны отличаться. Например:

bounce-unfold-stunning-chute        process-cancel-stingy-facebooksymptom-untouched-unpaid-arena  >   process-cancel-stingy-twittersediment-tweak-annually-koala       process-cancel-stingy-gmail

4.По возможности используйте двухфакторную / многофакторную аутентификацию.

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

Примечание: рекомендую использовать andOTP (или любые другие приложения на основе TOTP), поскольку его нельзя подделать или подсмотреть на заблокированном экране, как SMS OTP, и для него не требуется мобильная сеть или подключение к интернету. Вы также можете использовать биометрию (отпечаток пальца или распознавание лица).

Ух. Насколько реально вообще использовать длинный пароль для несметного количества сайтов, чтобы все они существенно отличались друг от друга, и при этом помнить каждый? Безопасность способна обеспечить серьёзную головную боль!

[Enter] Менеджер паролей

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

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

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

Ура, я в безопасности!

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

Что, если:

  • Ваш главный пароль (пароль к вашему менеджеру паролей) скомпрометирован из-за нарушения безопасности или вы оставили его в виде открытого текста письме, заметках или другом приложении?

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

Ответ: тыоблажался.

Когда кладёшь все яйца в одну корзину, то рискуешь, что все они могут уйти в небытие одним махом.И что тогда делать?

Пароли как крестраж

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

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

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

До:

#Как хранится в диспетчере паролейЛогин: rickПароль: rollthepeople1732#Фактически выглядитЛогин: rickПароль: rollthepeople1732

Теперь:

#Как хранится в диспетчере паролей Логин: rickpassword: roll-the-people-venus#Как хранится в вашей головеКрестраж: papel#Фактически выглядит Логин: rickПароль: roll-the-people-venuspapel

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

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

Последний момент

Безопасность никогда не бывает абсолютной. Можно попытаться защитить систему настолько, насколько это в принципе возможно. Но не стоит говорить, что она полностью безопасна (если вы видите, что кто-то утверждает обратное, то это обычно означает, что он пускает пыль в глаза). Если мы не можем сделать систему полностью безопасной, лучше всего сделать её как можно более безопасными. И хороший способ добиться этого: Глубокая защита. Убедитесь, что даже если один уровень безопасности будет нарушен, существуют другие. Создание многослойной защиты для смягчения возможного ущерба - это то, чего пытаются добиться многие специалисты по информационной безопасности.

Резюмируем

  1. Используйте хороший менеджер паролей.

  2. Используйте TOTP/биометрию вместо OTP на основе SMS.

  3. Используйте крестраж для наиболее важных учёток.

P.S. Имейте в виду, что крестражирование работает нормально только до тех пор, пока вы не подключите свой мозг к NeuraLink и случайно не загрузите свои мысли в интернет, где все смогут их увидеть ;).


Что ещё интересного есть в блогеCloud4Y

В Китае создали настольный квантовый компьютер стоимостью $5000

Тим Бернерс-Ли предлагает хранить персональные данные в подах

Виртуальные машины и тест Гилева

Создание группы доступности AlwaysON на основе кластера Failover

Как настроить SSH-Jump Server

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

Подробнее..

Интернет вещей по-русски. Процедура активации OpenUNB

28.02.2021 12:13:00 | Автор: admin

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


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


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


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


В OpenUNB активация устройства производится пользователем. Также необходим доверенный канал между пользователем и сервером сети. Схема взаимодействия представлена ниже:


image


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


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


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


Рассмотрим подробно процедуру со стороны устройства и со стороны сервера.


Со стороны устройства процедура выглядит так:


  1. проверяется текущее значение счетчика активаций Na. Если счетчик активаций уже достиг максимально возможного значения, то данное устройство больше не может использоваться, и выключается;
  2. увеличивается значение счетчика активаций: Na = Na + 1;
  3. вырабатывается ключ активации Ka;
  4. вырабатывается ключ расчета имитовставки Km для эпохи Ne = 0;
  5. формируется служебный пакет активации, в поле MACPayload которого содержится текущее значение счетчика активаций Na, а в качестве адреса указывается DevAddr0 = CRC24(DevID). При этом поле MACPayload передается в открытом виде (не шифруется), а поле имитовставки MIC рассчитывается на ключе Km для номера Nn = 0. Сформированный служебный пакет активации должен быть отправлен MAX_PKT_TX_NUM раз подряд для повышения вероятности его доведения;
  6. устройство считает активацию успешно завершенной и может передавать пакеты полезных данных.

Напомним формат пакета OpenUNB:
image


Сервер по приему пакета активации ищет адрес из пакета в списке адресов активированных устройств. Для каждого из найденных совпадений:


  1. сохраняется полученное значение счетчика активаций устройства Na. Если для данного устройства ранее уже осуществлялась успешная активация, то сервер должен дополнительно проверить, что текущее значение Na больше чем значение Na, полученное при предыдущей успешной активации. Если эта проверка завершается неуспешно, то сервер переходит к следующему найденному устройству;
  2. вырабатывается ключ активации Ka;
  3. вырабатывается ключ расчета имитовставки Km для эпохи Ne = 0;
  4. для пакета проверяется совпадение имитовставки MIC на ключе Km для номера Nn = 0.

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


Детали работы процедур активации OpenUNB смотрите в первоисточнике на сайте Сколтеха.


Реализованные процедуры активации и другие процедуры безопасности доступны в исходниках здесь.


Наш бессменный мастер Интернета вещей deef137 всегда на связи и готов помочь с вопросами по коду.

Подробнее..

Интернет вещей по-русски. Безопасность в OpenUNB

08.03.2021 14:16:44 | Автор: admin

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


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


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


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



а также изучить первоисточник на сайте Сколтеха.


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


Чтобы обеспечить базу безопасности, у каждого устройства и сервера должно быть что-то общее, секретное, которое никто не знает. В OpenUNB это секретный ключ шифрования K0, имеющий длину k, равную 128 или 256 бит. Весь остальной протокол должен быть сделан так, чтобы этот базовый, основной ключ не стал бы известен никому никаким образом, а информация при этом была защищена. Поэтому базовый ключ претерпевает такое множество преобразований в своем стремлении встретиться с информацией.


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


В недрах устройства и сервера OpenUNB есть счетчик активаций Na и счетчик эпох Ne, которые остаются примерно одинаковыми в процессе работы системы. Сначала вырабатывается ключ активации:


$ Ka = CTR (K0, Na || 0^{n/2-16}, 0^k).$


Потом уже по ключу активации вырабатываются рабочие ключ шифрования Km и ключ имитозащиты Ke:


$ Km = CTR (Ka, 0x02 || Ne || 0^{n/2-32}, 0^k),$


$ Ke = CTR (Ka, 0x03 || Ne || 0^{n/2-32}, 0^k).$


Для криптографических преобразований разработчики OpenUNB рекомендуется использовать блочный шифр Магма, который имеет длину блока n = 64 бита и длину ключа k = 256 бит, определенный в стандарте ГОСТ Р 34.12-2015.


Шифрование выглядит так:


$ EncryptedMACPayload = CTR (Ke, Nn || 0^{n/2-16}, MACPayload),$


где Nn номер пакета, а выработка имитовставки так:


$MIC = CMAC24 (Km, P),$


где значение вектора P зависит от длины блока n и длины поля MACPayload. Пусть len
однобайтная целочисленная беззнаковая переменная, равная длине полезных данных
MACPayload в битах (переменная len может принимать значения 16 или 48), тогда:


если len = 48 и n = 64, то


$P = DevAddr || MACPayload || Nn || 0^{2n-len-48} || len;$


в остальных случаях


$P = DevAddr || MACPayload || Nn || 0^{n-len-48} || len.$


Процедура CMAC24 здесь это криптопреобразование "режим выработки имитовставки" согласно ГОСТ.


Далее эти поля вставляются на свои места. Напомним схему формирования пакета:
image


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


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


Как всегда, исходники крипто-преобразований от deef137 доступны на Github.

Подробнее..

Перевод Как хакнуть Github и заработать 35000?

12.04.2021 18:13:34 | Автор: admin

Когда я нашёл эту уязвимость и сообщил о ней, она стала моим первым оплаченным баг-репортом на HackerOne. $35,000 это также самая высокая награда, которую я получил от HackerOne (и я считаю, что самая высокая оплата от GitHub на сегодня). Многие найденные ошибки, кажется, это удача и интуиция, вместе взятые. В этом посте я расскажу, как мыслил, приближаясь к цели.


Как началась история

Ковид ударил весной, в первый год старшей школы. От нечего делать между онлайн-занятиями я начал охоту за багами. Конкретно эта награда была за сообщение об уязвимости приватных страниц Github в рамках программы Баг Баунти. В частности, было и два бонуса CTF (capture the flag состязание по типу захвата флага, здесь в информационной безопасности):

  • $10000 чтение флага flag.private-org.github.io без взаимодействия с пользователем. Бонус в $5000 за то, что флаг читается с аккаунта внутри приватной организации.

  • $5000: чтение флага flag.private-org.github.io через взаимодействие с пользователем.

Поток аутентификации

Страницы GitHub размещаются в отдельном домене github.io, поэтому куки-файлы аутентификации github.com не отправляются на сервер приватных страниц. Таким образом, аутентификация частной страницы не имеет возможности определить личность пользователя без дополнительной интеграции с github.com, поэтому GitHub создал собственный поток аутентификации. И ввёл возможность существования багов. На момент отчёта этот поток выглядел так:

А теперь подробнее.

При посещении приватной страницы сервер проверяет, существует ли файл куки __Host-gh_pages_token. Если этот файл не установлен или установлен неправильно, сервер приватной страницы перенаправит на https://github.com/login. Этот начальный редирект также устанавливает nonce, который хранится в куки __Host-gh_pages_session.

Обратите внимание, что этот куки использует префикс куки __Host-, который, в теории, в качестве дополнительной защиты в глубину, предотвращает его установку из JS с родительского домена.

/login перенаправляет на /pages/auth?nonce=&page_id=&path=. Затем эта конечная точка генерирует временный куки-файл аутентификации, который она передаёт https://pages-auth.github.com/redirect в параметре token; nonce, page_id, и path присылаются аналогично.

/redirect просто перенаправляет на https://repo.org.github.io/__/auth. Эта последняя конечная точка затем устанавливает куки аутентификации для домена repo.org.github.io, __Host-gh_pages_token и __Host-gh_pages_id. Также вместе с ранее установленным __Host-gh_pages_session на валидность проверяется nonce.

На протяжении всего потока аутентификации такая информация, как исходный путь запроса и идентификатор страницы, хранится в параметрах запроса path и page_id соответственно. Nonce также передаётся в параметре nonce. Хотя поток аутентификации, возможно, немного изменился (отчасти из-за этого отчёта), общая идея остаётся прежней.

Эксплоит

CRLF возвращается

Первая уязвимость CRLF-инъекция в параметре page_id запроса https://repo.org.github.io/__/auth.

Возможно, лучший способ найти уязвимые места поиграть. Исследуя поток аутентификации, я заметил, что парсинг page_id, похоже, игнорировал пробельные символы. Интересно, что он также рендерил параметр непосредственно в заголовок Set-Cookie. К примеру, page_id=12345%20 вернул это:

Set-Cookie: __Host-gh_pages_id=12345 ; Secure; HttpOnly; path=/

Псевдокод предположительно такой:

page_id = query.page_iddo_page_lookup(to_int(page_id))set_page_id_cookie(page_id)

Другими словами, page_id преобразуется в целое число, а также отображается напрямую в заголовок Set-Cookie. Проблема была в том, что мы не можем отобразить текст напрямую. Несмотря на то, что у нас была классическая CRLF-инъекция, размещение любых непробельных символов привело к поломке парсинга целого. Мы могли бы прервать поток аутентификации, отправив page_id=12345%0d%0a%0d%0a, но, кроме интересного ответа, никакого немедленного воздействия не было.

; Secure; HttpOnly; path=/Cache-Control: privateLocation: https://83e02b43.near-dimension.github.io/X-GLB-L

Дополнительное примечание: заголовок Location: был добавлен после заголовка Set-Cookie, поэтому наш ответ Location выталкивает за пределы отправленных HTTP-заголовков. Это редирект на 302, но, несмотря на это, заголовок Location игнорируется и отображается содержимое тела.

Из грязи в князи

Немного просмотрев на GitHub Enterprise (который дал доступ к исходному коду), я заподозрил, что сервер приватных страниц реализован на Nginx OpenResty. Будучи относительно низкоуровневым, возможно, он имел проблемы с нулевыми байтами. А попытка не пытка, правильно?

Оказалось, что добавление нулевого байта прерывает парсинг целого. Другими словами, можно передать такую полезную нагрузку:

"?page_id=" + encodeURIComponent("\r\n\r\n\x00<script>alert(origin)</script>")

А вот и XSS!

Обратите внимание, что, если в заголовке есть нулевой байт, ответ будет отклонён. Таким образом, нулевой байт должен прийти в начале тела (это означает, что мы не можем выполнить атаку через инъекцию в заголовок).

Мы добились выполнения произвольного JavaScript на странице приватного домена. Единственная проблема нужен способ обойти nonce. Параметры page_id и path известны, а nonce не позволяет нам отправлять жертв вниз по потоку аутентификации с отравленным page_id. Нам нужно либо зафиксировать, либо спрогнозировать nonce.

Обходим nonce

Первое наблюдение поддомены одной организации могут устанавливать куки-файлы друг на друга. Так происходит потому, что *.github.io нет в публичном списке суффиксов. Таким образом установленные на private-org.github.io куки передаются на private-page.private-org.github.io.

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

Ну, ладно... неправильно говорить не во всех. Похоже, в смысле этого обхода уязвим только IE. Придётся постараться. А что, если атаковать сам nonce? генерация выглядит надёжной, и, если честно, криптография не моя сильная сторона. Найти обход применяемой в nonce энтропии, несмотря ни на что, это казалось маловероятным. Как же тогда зафиксировать nonce?

Вернёмся к истокам RFC. В конце концов, я наткнулся на интересную идею как нормализовать куки? В частности, как следует обращаться с куки с учётом верхнего регистра. "__HOST-" это то же самое, что "__Host-"? Легко убедиться, что в браузерах с куками разного регистра обращаются по-разному:

document.cookie = "__HOST-Test=1"; // worksdocument.cookie = "__Host-Test=1"; // fails

Оказывается, сервер приватных страниц GitHub при разборе куки-файлов игнорирует заглавные буквы. И у нас есть префиксный обход. А теперь собираем доказательство концепции атаки XSS!

<script>const id = location.search.substring("?id=".length)document.cookie = "__HOST-gh_pages_session=dea8c624-468f-4c5b-a4e6-9a32fe6b9b15; domain=.private-org.github.io";location = "https://github.com/pages/auth?nonce=dea8c624-468f-4c5b-a4e6-9a32fe6b9b15&page_id=" + id + "%0d%0a%0d%0a%00<script>alert(origin)%3c%2fscript>&path=Lw";</script>

Уже этого достаточно, чтобы заработать бонус в $5000. Но я хотел посмотреть, получится ли продвинуться дальше.

Отравление кэша

И вот ещё один недостаток дизайна выяснилось, что в ответ на конечную точку /__/auth? кэшировалось только целое значение page_id. Само по себе это безвредно: установленный этой конечной точкой токен скопирован на личную страницу и не имеет никаких других привилегий.

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

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

Злоумышленник контролирует unprivileged.org.github.io и хочет добраться до privileged.org.github.io. Он атакует поток аутентификации unprivileged.org.github.io и полезная нагрузка XSS кэшируется.

Когда привилегированный пользователь посещает unprivileged.org.github.io, он подвергается XSS атаке на домен unprivileged.org.github.io. Куки могут устанавливаться на общем родительском домене org.github.io, поэтому теперь злоумышленник может атаковать privileged.org.github.io.

Эти действия позволяют любому злоумышленнику с разрешениями на чтение приватной страницы постоянно атаковать поток аутентификации этой страницы. Ё-моё!

Публичные и приватные страницы

Чтобы получить бонус 15000 долларов, нужно выполнить эту атаку с учётной записи пользователя, которого в организации нет. И нам везёт: мы можем злоупотребить тем, что кажется ещё одной ошибкой конфигурации разделением страниц на публичные и приватные.

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

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

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

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

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

Заключение

Этой уязвимости присвоили высокий приоритет, базовая выплата составила 20 000 долларов, а с бонусом CTF мы заработали 35 000 долларов. Довольно круто, что такая относительно малоизвестная уязвимость, как инъекция CRLF, обнаружилась на GitHub. Хотя большая часть кода написана на Ruby, некоторые компоненты, такие как аутентификация приватной страницы, написаны не на этом языке и могут быть уязвимы к низкоуровневым атакам. В общем, везде, где есть сложные взаимодействия, ошибки только ждут, чтобы мы их нашли.

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

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Как ускорить аутентификацию и снизить потребление памяти в 5 раз? Наймите дворецкого

07.05.2021 12:20:51 | Автор: admin

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

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

Итак, овсянка, сэр.

По мере роста популярности платформы система аутентификации перестала соответствовать нашим требованиям, как и некоторые другие части нашей архитектуры. Когда весной 2020 года в базе Учи.ру стало больше 11 млн активных пользователей (8 млн учеников, примерно 350 тыс. учителей и около 3,5 млн родителей), существующая реализация стала медленной, непрозрачной и потребляла слишком много памяти. Мы решили ее обновить.

Поставили перед собой следующие цели:

  • повысить производительность;

  • внедрить новые технологии защиты учетных данных;

  • выделить аутентификацию из монолита в микросервис;

  • подключить мобильное приложение.

При этом хотелось иметь возможность поддерживать функции, которые до этого не реализовывались.

В список новых функций попали:

  • принудительное отключение пользователя;

  • блокировка аккаунта;

  • верификация;

  • шифрование паролей учеников;

  • поддержка jwt-токенов и двухфакторной аутентификации;

  • интеграция с социальными сетями;

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

Сложности работы с таблицами. Роли пользователей

Долгая аутентификация

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

Проблема уникальности почты и логина

Если родитель одновременно является учителем и хочет зарегистрироваться на Учи.ру, он должен завести две учетные записи. Это значит, что его e-mail будет числиться в двух разных таблицах. Та же история может происходить, если один человек является и сотрудником, и родителем или и сотрудником, и учителем и т. д. Если e-mail один, то сложно определить, какого именно пользователя нужно аутентифицировать.

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

Теперь мы используем Butler

Чтобы исправить ситуацию, мы решили вынести аутентификацию в отдельный сервис. Для этого был создан Butler. Саму аутентификацию было решено проводить на базе открытой библиотеки Ruby под названием rodauth. Ее, конечно, пришлось немного доработать, но в целом решение подходило. Параллельно с улучшением своего продукта мы внесли небольшой вклад в развитие open source-сообщества.

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

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

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

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

Небольшой тюнинг решения

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

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

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

Обновление камень преткновения

Обновлять исходный код open-source компонента нужно аккуратно, потому что в открытых проектах вопросы обратной совместимости не всегда оказываются решены полностью. Так, нам нужно было установить обновление, которое требовалось для внедрения очередной фичи. Но с этим обновлением возникал обязательный параметр связи между access-токеном и refresh-токеном. Раньше он был необязательным и от нашего внимания ускользнул. Это значит, что все выданные токены перестали бы работать разом, если бы мы накатили это обновление. То есть, если бы мы сразу обновили всю систему, это привело бы к сбросу всех активных сессий.

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

Криптография и защита от брутинга

Хранить логины и пароли в новой базе данных было решено в зашифрованном виде. Тогда дополнительным тормозом стал один из наиболее используемых алгоритмов в экосистеме Ruby BCrypt.

Его реализация на Ruby отнимала слишком много процессорного времени, затрачивая 250 мс на создание хеша со стандартным костом, равным 12. Зачастую подобную операцию необходимо проводить дважды в течение цикла вопрос-ответ, поскольку требуется проверка на использование этого же пароля пользователем прежде. Вкупе со множественным использованием колбеков в монолите ситуация стала приводить к большому времени ожидания внутри транзакций БД (idle in transaction), что начало сказываться на производительности системы. На этих самых колбеках висело слишком много бизнес-логики, что не позволило свести проблему к простому рефакторингу.

Выходом из положения стала смена алгоритма шифрования на более гибкий, который поддерживает конфигурацию как по затрачиваемой памяти, так и временному ресурсу. Мы взяли открытый алгоритм Argon2 и постепенно мигрировали пользователей с одного на второй, благо в rodauth имелись зачатки функционала для осуществления плавного перехода. Для этого потребовалось внести изменения в саму библиотеку rodauth. К счастью, Jeremy Evans ее автор оказался очень открытым человеком, пошел нам навстречу.

В сервисе rodauth также нашлось встроенное решение по защите от брутинга паролей. После определенного количества попыток аккаунт блокируется на некоторое время. Разблокировку можно провести за счет подтверждения через e-mail или вручную.

Перенос аккаунтов

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

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

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

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

Результаты

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

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

Подробнее..

Интеграция SAML в Zimbra OSE

16.06.2021 14:10:53 | Автор: admin
Технология единого входа обладает массой преимуществ по сравнению с классическими методами аутентификации, главное из которых заключается в том, что именно SSO обеспечивает наилучший баланс между удобством пользователя и информационной безопасностью предприятия. Ранее мы уже рассказывали о том, как реализовать SSO в Zimbra OSE при использовании аутентификации в Active Directory с помощью Kerberos. На этот раз мы расскажем о том, как внедрить Zimbra OSE другую технологию единого входа SAML на примере провайдера Okta.

image

Единый вход с помощью SAML в Zimbra OSE доступен только для пользователей Zextras Suite Pro.

Подготовка к интеграции

В первую очередь для включения интеграции в SAML, необходимо пропатчить NGINX. Для этого в папке /opt/zimbra/conf/nginx/templates/ отредактируйте поочередно файлы:

  • nginx.conf.web.http.default.template
  • nginx.conf.web.http.template
  • nginx.conf.web.https.default.template
  • nginx.conf.web.https.template

Во всех файлах в разделе location ^~ /zx/ замените содержимое на

location ^~ /zx/

{

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_set_header Host $http_host;

proxy_set_header X-Forwarded-Proto $scheme;

proxy_set_header X-Forwarded-Port $server_port;

proxy_pass ${web.upstream.zx};

}


Эти изменения нужны для того, чтобы составлять полноценные URL-запросы Protocol X и X-Port.

Также необходимо активировать движок аутентификации от Zextras на уровне домена. Сделать это может администратор сервера, введя в командной строке команду zmprov modifyDomain example.ru zimbraAuthMech custom:zx.

Создание приложения в Okta

В том случае, если вы ранее не использовали SAML для доступа к ресурсам компании, вам придется создать собственное приложение для аутентификации пользователей. Для того, чтобы создать такое приложение в Okta:

1. Зарегистрируйтесь в качестве разработчика на сайте okta.com

2. В личном кабинете нажмите на кнопку Create App Integration



3. В открывшемся списке выберите SAML 2.0 и нажмите Next



4. В следующем окне укажите название своего приложения, выберите иконку и настройте его видимость и нажмите кнопку Next, когда всё будет готово



5. В следующем окне:

  1. В качестве SSO URL укажите адрес вашего сервера с аппендиксом /zx/auth/saml
  2. В качестве Audiend URI укажите адрес вашего сервера с аппендиксом /zx/auth/samlMetadata
  3. В качестве Name ID Format укажите EmailAddress
  4. Нажмите кнопку Next



6. В мини-опросе выберите первый вариант ответа и нажмите кнопку Finish



7. Скачайте метаданные своего приложения SAML



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

Экспорт учетных записей из домена Zimbra OSE

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

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



Импортируйте полученный CSV в приложение SAML с помощью соответствующего инструмента в личном кабинете разработчика.

Интеграция приложения в Zimbra OSE

Чтобы интегрировать приложение SAML в Zimbra OSE, вам потребуются данные из скачанного ранее файла с метаданными приложения.

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

Для того, чтобы выполнить интеграцию в автоматическом режиме, введите команду zxsuite auth saml import example.ru url dev-3299935.okta.com/app/exkvjcggn7C7jrhc75d6/sso/saml/metadata. Если вы используете собственный сервер SAML с самоподписанными сертификатами, используйте параметр allow_insecure true для пропуска проверки подлинности SSL-сертификата.

Чтобы провести интеграцию в ручном режиме, экспортируйте настройки SAML по умолчанию при помощью команды zxsuite auth saml get example.ru export_to /tmp/saml.json. Откройте полученный файл /tmp/saml.json в любом редакторе и добавьте в него следующие данные, заменяя строки отмеченные знаками >> << данными из файла с метаданными. В нашем случае добавленные строки будут выглядеть следующим образом:

sp.nameidformat:urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress ,
sp.entityid: >>example.ru/zx/auth/samlMetadata?domain=example.ru<<,
sp.assertion_consumer_service.url: >>example.ru/zx/auth/saml<<,
idp.single_sign_on_service.url: >>dev-3299935.okta.com/app/dev-3299935_zextrassamlintegration_1/exkvjcggn7C7jrhc75d6/sso/saml<<,
idp.entityid: >>www.okta.com/exkvjcggn7C7jrhc75d6<<,
idp.x509cert: >>MIIDpjCCAo6gAwIBAgIGAXmC9e8bMA0GCSqGSIb3DQEBCwUAMIGTMQswCQYDVQQGEwJVUzETMBEG A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEU MBIGA1UECwwLU1NPUHJvdmlkZXIxFDASBgNVBAMMC2Rldi0zMjk5OTM1MRwwGgYJKoZIhvcNAQkB Fg1pbmZvQG9rdGEuY29tMB4XDTIxMDUxOTA0NDkyNloXDTMxMDUxOTA0NTAyNlowgZMxCzAJBgNV BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ0wCwYD VQQKDARPa3RhMRQwEgYDVQQLDAtTU09Qcm92aWRlcjEUMBIGA1UEAwwLZGV2LTMyOTk5MzUxHDAa BgkqhkiG9w0BCQEWDWluZm9Ab2t0YS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQCOJA7bhf/LO89VpuGTHur77RbwKlJg3Eni/P4JKowSVrQD6PghwprCdzThyTsKWcHwESZoYwEL WdrZ6CVzDZWAegWJnaJivfiFlFjsEZ15UHOGizMBM3VI0ePWjaWJ6O2DM9BID2mGULnXUDbQXbf6 rE1EHxzlxzCKIBWmT8ut/JsA/lmBm0YNi4BKfP06KXCLianxoH+fEETNd/NH2mXwgHdxMV1BS/mm TAHSJtkDfWxTM+dTGngrjMANKvmChGjSO1ZXFs/pm+vx0o6ffYcoeXnfgodBX3FZ7aTFBTk0s5Se Wms1utjfa8qhHbrolErqqIc1PPBngEFvzcLjFAfRAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAByU jjdAc5tdH+QFAHS0CJNYa9VNaapxuEFrlR3ZdAztIaczKUqYfHqHdXuDHYCjdHXhLFHwntBsnphk M2sk8D2zG0wpoYsEA3IrvbXoTwwqDzACpLF37S7Pfn0RjE5IvvJ9WP4DoZa9ikM/p0N+H7fpqkU2 xavoiNGOMqot9xpWrytM0P+luXereriOOzVaBS1+DuhA4INhze5luyc52X18T4HrJ3iGivfXR2os L8/PI4gZwR956Ju8tDEcmFVCelLN4FlN3ITogPK+SyKHhlTBuSGHidrGKQJBRmkLhk6lhKWTHjWP mI88ECqrA63+QvxU4KRUl1zzRgKVwrgzos4=<<

Сохраните внесенные в файл изменения и импортируйте его в Zimbra OSE с помощью команды zxsuite auth saml import example.ru /tmp/saml.json



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

По всем вопросам, связанными c Zextras Suite Pro и Team Pro вы можете обратиться к Представителю компании Zextras Technology Екатерине Триандафилиди по электронной почте ekaterina.triandafilidi@zextras.com
Подробнее..

Перевод Простое ускорение Java с помощью Quarkus и JHipster

01.06.2021 20:15:10 | Автор: admin

К старту курса о разработке на Java делимся переводом вводной статьи о Quarkus "родной" для Kubernetes Java-платформе для создания высокопроизводительных веб-, бессерверных (serverless) и нативных приложений (оптимизированных для используемых микропроцессоров). В ней используются предварительная компиляция AOT и агрессивная оптимизация, например сканирование путей к классам, перезагрузка конфигурации и предварительная конфигурация самозагрузки приложения в процессе сборки. Результатом становится впечатляющая скорость загрузки. Другими словами, приложения, созданные с Quarkus, запускаются не просто быстро, а очень быстро!


Так же как для платформ Spring и Micronaut, в Quarkus можно использовать преимущество GraalVM для преобразования JVM-приложений в нативные исполняемые файлы, что ещё больше повышает их быстродействие.

Такой прирост производительности позволяет этой Java-платформе конкурировать с бессерверными, облачными и созданными на основе Kubernetes средами, создавая приложения Supersonic Subatomic Java. В Quarkus используются стандарты Java (такие, как MicroProfile, JAX-RS), а также лучшие из существующих Java-библиотек (например, Hibernate и Vert.x). Есть даже поддержка аннотаций Spring.

Quarkus + JHipster = простое ускорение Java

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

JHipster это сопровождаемая сообществом разработчиков полнофункциональная платформа разработки, позволяющая создавать, развивать и развёртывать веб-приложения и ориентированные на микросервисы архитектуры. Стандартной серверной платформой в JHipster является Spring Boot, но постоянно появляются всё новые и новые возможности. Одним из таких вариантов стала blueprint-схема JHipster Quarkus.

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

Например, blueprint-схема Kotlin с JHipster является популярным дополнением, которое любят использовать разработчики. Использование blueprint-схемам многократно расширяет границы возможностей. Вот почему в JHipster есть даже реализации без Java (такие, как Node + NestJS и .NET Core). Эта публикация познакомит вас с основными шагами по использованию JHipster, blueprint-схемой Quarkus, а также протоколом OAuth для создания оптимизированного для работы на конкретных микропроцессорах и безопасного полнофункционального приложения.

Создание Java-приложения с Quarkus

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

Предварительные требования:

Установите JHipster и его blueprint-схему Quarkus, используя npm:

# Install JHipster globallynpm install -g generator-jhipster@6.10.5# Install the JHipster Quarkus blueprintnpm install -g generator-jhipster-quarkus@1.1.1

Команда jhipster-quarkus сокращение для jhipster --blueprints quarkus. Посмотреть все варианты её синтаксиса можно с помощью команды --help.

$ jhipster-quarkus --help

Создание приложения в среде JHipster Quarkus

mkdir okta-jhipster-quarkus-example && cd okta-jhipster-quarkus-example# oh-my-zsh users: take okta-jhipster-quarkus-example

Чтобы запустить мастер создания приложений, можно выполнить команду jhipster-quarkus:

jhipster-quarkus

В этой вводной статье основным вопросом будет выполнение аутентификации.

Среда JHipster Quarkus позволяет использовать JWT (с возможностью управления пользователями в базе данных приложений) или аутентификацию OAuth 2.0/OIDC с применением поставщиков идентификационной информации, таких как Keycloak и Okta. OIDC расшифровывается как OpenID Connect, этот протокол представляет собой тонкий слой поверх протокола аутентификации OAuth 2.0. Его основная задача обеспечить аутентификацию и идентификацию пользователя.

Ниже представлен пример ответов на вопросы мастера создания приложений.

После того как вы ответите на все эти вопросы, JHipster создаст код вашего приложения и выполнит команду npm install.

{  "generator-jhipster": {    "promptValues": {      "packageName": "com.mycompany.myapp",      "nativeLanguage": "en"    },    "jhipsterVersion": "6.10.5",    "applicationType": "monolith",    "baseName": "jhipster",    "packageName": "com.mycompany.myapp",    "packageFolder": "com/mycompany/myapp",    "serverPort": "8080",    "authenticationType": "oauth2",    "cacheProvider": "no",    "enableHibernateCache": true,    "websocket": false,    "databaseType": "sql",    "devDatabaseType": "h2Disk",    "prodDatabaseType": "mysql",    "messageBroker": false,    "buildTool": "maven",    "embeddableLaunchScript": false,    "useSass": true,    "clientPackageManager": "npm",    "clientFramework": "angularX",    "clientTheme": "none",    "clientThemeVariant": "",    "creationTimestamp": 1614834465776,    "jhiPrefix": "jhi",    "entitySuffix": "",    "dtoSuffix": "DTO",    "otherModules": [      {        "name": "generator-jhipster-quarkus",        "version": "1.1.1"      }    ],    "enableTranslation": true,    "nativeLanguage": "en",    "languages": ["en"],    "blueprints": [      {        "name": "generator-jhipster-quarkus",        "version": "1.1.1"      }    ]  }}

В этом файле содержатся все ответы на исходные вопросы мастера JHipster, что позволит создать приложение без дополнительных запросов.

Убедитесь, что выполняемая с помощью Keycloak аутентификация OAuth 2.0/OIDC действительно работает

Помимо прочих файлов JHipster Quarkus создаёт файлы для инструментального средства Docker Compose, помогающие загрузить среду разработки, настроенную для вашего только что созданного приложения. При этом даже выполняется импорт данных Keycloak, заданных по умолчанию для пользователей и приложений, и вам не придётся делать это самим.

https://gitlab.webant.ru/russia_quiz/frontend/-/merge_requests

Если Keycloak запущен и работает, вы сможете выполнить вход в систему. Запустите ваше приложение с помощью Maven:

./mvnw

Вы можете видеть, что приложение запускается за 3,351 с, также выводится обширный список расширений Quarkus (включая oidc). Перейдите по адресу http://localhost:8080 в предпочитаемом вами браузере и нажмите ссылку sign in (вход).

Вы будете перенаправлены в Keycloak для входа в систему. При запросе идентификационных данных введите admin/admin.

После успешного прохождения аутентификации вы будете перенаправлены обратно в ваше приложение Quarkus.

Как работает поддержка протокола аутентификации OAuth 2.0 в JHipster Quarkus

Одной из проблем при разработке blueprint-схем JHipster, таких как Quarkus, является необходимость найти правильный баланс между повторным использованием существующих механизмов и добавлением индивидуальных реализаций.

С самого первого дня своего появления JHipster осуществлял интеграцию всех современных платформ для создания веб-приложений (Angular, React или даже Vue.js), совмещая их с фактически стандартными Java-технологиями, такими как Spring Boot и Spring Cloud.

В реализации JHipster Quarkus OAuth 2.0 за основу взято URI-перенаправление login/oauth2/code/oidc, предполагающее использование платформы аутентификации Spring Security. Настоятельно рекомендуем выполнять аутентификации на стороне сервера, поскольку это намного безопаснее (так как у браузера нет необходимости управлять какими-либо идентификационными данными и хранить какие-либо маркеры доступа).

В среде JHipster Quarkus, чтобы повторно использовать без изменений клиентские приложения и реализовать на серверной стороне механизм аутентификации по протоколу OAuth 2.0, в бэкенде должны быть открыты два HTTP-маршрута. Вот почему в JHipster Quarkus предусмотрен контроллер UserOauth2Controller и настраиваемые свойства Quarkus OIDC, позволяющие обеспечить правильную работу всего механизма.

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

Объединение JHipster Quarkus с сервисом Okta

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

Использование инфраструктуры Okta CLI для конфигурирования JHipster

Инфраструктура Okta CLI автоматизирует для вас все конфигурации JHipster и Okta. Для установки Okta CLI можно воспользоваться популярными менеджерами пакетов.

macOS (с помощью Homebrew):

brew install --cask oktadeveloper/tap/okta

Linux (с помощью Flatpak):

# Add Flathub repoflatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo# install the packageflatpak install com.okta.developer.CLI# add this to your appropriate dot filealias okta="flatpak run com.okta.developer.CLI"

Windows (с помощью Chocolatey):

choco install okta -version 0.8.0

Вы также можете просто передать его в оболочку bash:

curl https://raw.githubusercontent.com/okta/okta-cli/master/cli/src/main/scripts/install.sh | bash

Если у вас ещё нет аккаунта разработчика в Okta, откройте терминал, перейдите в каталог приложения Quarkus и выполните okta register. Если у вас есть аккаунт, выполните okta login.

$ okta registerFirst name: DanielLast name: PetismeEmail address: daniel.petisme@gmail.comCompany: OktaCreating new Okta Organization, this may take a minute:OrgUrl: https://dev-9323263.okta.comAn email has been sent to you with a verification code.Check your emailVerification code: 232819New Okta Account created!Your Okta Domain: https://dev-9323263.okta.comTo set your password open this link:https://dev-9323263.okta.com/welcome/drpt2SjbRAPR-gvVHhnm

Если у вас уже есть аккаунт разработчика Okta, выполните команду okta login. Затем из каталога приложения Quarkus выполните okta apps create jhipster. Примите предлагаемые по умолчанию предложения для перенаправления URI.

$ okta apps create jhipsterApplication name [okta-jhipster-quarkus-example]:Redirect URICommon defaults:  Spring Security - http://localhost:8080/login/oauth2/code/okta  Quarkus OIDC - http://localhost:8080/callback  JHipster - http://localhost:8080/login/oauth2/code/oidcEnter your Redirect URI(s) [http://localhost:8080/login/oauth2/code/oidc, http://localhost:8761/login/oauth2/code/oidc]:Enter your Post Logout Redirect URI(s) [http://localhost:8080/, http://localhost:8761/]:Configuring a new OIDC Application, almost done:Created OIDC application, client-id: 0oa5ozjxyNQPPbKc65d6Creating Authorization Server claim 'groups':Adding user daniel.petisme@gmail.com to groups: [ROLE_USER, ROLE_ADMIN]Creating group: ROLE_USERCreating group: ROLE_ADMIN

Конфигурация приложения Okta записывается здесь: /Users/daniel/workspace/okta-jhipster-quarkus-example/.okta.env

ПРИМЕЧАНИЕ: идентификаторы URI, перенаправленные http://localhost:8761*, предназначены для реестра JHipster, который часто используется при создании микросервисов с помощью JHipster. В инфраструктуре Okta CLI они добавляются по умолчанию. Они не требуются для приложения, создаваемого в этой вводной статье, но если их оставить, то никакого вреда точно не будет.

Инфраструктура Okta CLI создаст файл .okta.env в текущем каталоге. Если посмотреть на него, то вы увидите, что в нём содержатся несколько ключей и значений, предназначенных для протокола OIDC.

$ cat .okta.envexport QUARKUS_OIDC_AUTH_SERVER_URL="http://personeltest.ru/aways/dev-9323263.okta.com/oauth2/default"export QUARKUS_OIDC_CLIENT_ID="0oa5ozjxyNQPPbKc65d6"export QUARKUS_OIDC_CREDENTIALS_SECRET="KEJ0oNOTFEUEFHP7i1TELLING1xLm1XPRn"export QUARKUS_OIDC_AUTHENTICATION_REDIRECT_PATH="/login/oauth2/code/oidc"export JHIPSTER_OIDC_LOGOUT_URL="http://personeltest.ru/aways/dev-9323263.okta.com/oauth2/default/v1/logout"

Установите файл, чтобы задать переменные среды, и запустите ваше приложение с помощью Maven.

source .okta.env./mvnw

Обязательно добавьте \*.env в ваш файл .gitignore, чтобы в коммиты не попадал ваш секрет клиента.

Как только приложение будет запущено, в окне в режиме инкогнито откройте http://localhost:8080 и выполните вход. Вам будет предложено ввести свои идентификационные данные Okta.

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

Инфраструктура Okta CLI упрощает конфигурирование JHipster и выполняет следующие полезные операции.

  1. Создаётся приложение OIDC с правильным перенаправлением URI.

  2. Заводятся группы ROLE_ADMIN и ROLE_USER, требуемые для JHipster.

  3. Ваш текущий пользователь добавляется в группы ROLE_ADMIN и ROLE_USER.

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

Но вдруг вы не любите работать из командной строки? Не паникуйте, тут есть кому прикрыть вашу спину! Инфраструктура Okta CLI проста в использовании, но для тех, кому это необходимо, есть возможность выполнить настройки с помощью интерфейса пользователя. Именно поэтому я так подробно рассматриваю каждый шаг по настройке приложения OIDC, работающего с JHipster Quarkus.

Использование консоли разработчика Okta для настройки JHipster

Если у вас нет аккаунта разработчика Okta, необходимо нажать ссылку sign up (вход). Тут нет ничего сверхсложного: просто укажите имя, фамилию, адрес электронной почты, выберите надёжный пароль и всё вы готовы двигаться дальше. Выполнив вход в систему, вы попадаете в консоль разработчика:

Разверните вложенное меню Applications (Приложения) на панели навигации слева, затем выберите в меню Applications > Create App Integration (Приложения > Создать интеграцию приложений), чтобы запустить мастер создания приложений.

Выберите OIDC и Web Application. Затем нажмите кнопку Next (Далее).

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

  • Name (Имя): можете указать любое имя на свой вкус, но разве JHipster Quarkus чем-то не подходит?

  • Login redirect URIs (Перенаправление URI при входе): определяет, будет ли Okta выполнять перенаправление в браузере клиента после аутентификации. Установите для него http://localhost:8080/login/oauth2/code/oidc, именно это значение настроено по умолчанию.

  • Logout redirect URIs (Перенаправление URI при выходе): http://localhost:8080 указывается, куда будет перенаправляться пользователь после выполнения выхода.

  • Group assignments (Назначения групп): определяет, какие группы могут использовать это приложение.

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

Наиболее важными являются следующие значения:

  • идентификационные данные клиента (ID и секрет клиента). Они позволяют приложению Java выполнять аутентификацию в сервисах Okta для последующей обработки потоков аутентификации и авторизации пользователей;

  • домен Okta, из которого Quarkus будет выводить конечные точки адресов URL для протоколов OAuth/OIDC.

Создание групп пользователей

Теперь настало время для создания групп пользователей. По умолчанию для JHipster требуются две следующие группы:

  • ROLE_USER: для аутентифицированных пользователей;

  • ROLE_ADMIN: для аутентифицированных пользователей с административными правами для этого приложения.

В консоли разработчика выберите в меню Directory > Groups (Каталог > Группы). Нажмите Add Group (Добавить группу) и создайте группу ROLE_ADMIN

Теперь добавьте группу ROLE_USER.

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

Создание пользователей

Чтобы увидеть различие между обычными и административным пользователями, создайте пользователей в каждой из групп. Используя консоль разработчика Okta, выберите в меню Directory > People (Каталог > Люди). Нажмите Add Person (Добавить человека). Начните с создания пользователя Administrator.

Основным моментом тут является привязка пользователя Administrator к группе ROLE_ADMIN. Чтобы определить исходный пароль, который пользователь должен будет изменить, исключительно в демонстрационных целях для данной вводной статьи использована стратегию выбора пароля Set by Admin (Задаётся администратором). В реальном проекте я рекомендую использовать стратегию Set by User (Задаётся пользователем) с активацией по электронной почте. Теперь добавим обычного пользователя.

Убедитесь, что пользователь User входит в группу ROLE_USER. Очень важно использовать действующий адрес электронной почты, так как он может понадобиться при восстановлении пароля. Выберите в меню Applications > JHipster Quarkus (Приложения > JHipster Quarkus) и нажмите Assignments (Назначения). Назначьте группам пользователей, которых только что создали.

Добавление заявки на группы к маркеру ID

Последнее, о чём необходимо вам позаботиться, это настроить заявку на группы, включающую группы пользователей в маркер ID. Выберите в меню Security > API (Безопасность > API), а затем нажмите default (по умолчанию). Щёлкните Claims > Add Claim (Заявки > Добавить заявку). Введите следующие значения:

  • Name (Имя): groups (группы);

  • Include in token type (Включить тип маркера): ID Token (Маркер ID);

  • Value type (Тип значения): groups (группы);

  • Filter (Фильтр): Matches regex with a value of .* (Соответствует регулярному выражению со значением .*).

Нажмите Create (Создать). Конфигурация Okta для JHipster готова!

Настройка Quarkus OIDC для Okta

В этот момент необходимо, чтобы приложение JHipster Quarkus уже было запущено и для использования Keycloak в качестве провайдера идентификационных данных для него. Давайте изменим настройки для работы с Okta. Во-первых, необходимо выйти из веб-приложения JHipster, чтобы предотвратить конфликт файлов cookie. Выберите Account > Sign Out (Аккаунт > Выход).

ПРИМЕЧАНИЕ: можно оставить приложение запущенным. Quarkus поддерживает работу в так называемом режиме для разработки (Dev Mode), обеспечивающем горячую перезагрузку любых исходных или ресурсных файлов при каждом их обновлении. Это исключительно удобно!

Откройте для редактирования файл src/main/resources/application.properties и найдите в нём раздел со следующей конфигурацией OIDC.

# OAuth 2.0 and OIDCquarkus.oidc.enabled=truequarkus.oidc.auth-server-url=http://localhost:9080/auth/realms/jhipster/%dev.quarkus.oidc.client-id=web_app%dev.quarkus.oidc.credentials.secret=web_appquarkus.oidc.application-type=hybridquarkus.oidc.authentication.scopes=profile,address,email,address,phone,offline_accessquarkus.oidc.authentication.cookie-path=/quarkus.oidc.authentication.redirect-path=/login/oauth2/code/oidcquarkus.oidc.authentication.restore-path-after-redirect=falsejhipster.oidc.logout-url=http://localhost:9080/auth/realms/jhipster/protocol/openid-connect/logout%test.quarkus.oidc.client-id=dummy%test.quarkus.oidc.application-type=service%test.jhipster.oidc.logout-url=some-dummy-logoutUrl

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

  • quarkus.oidc.auth-server-url: корневой URL для API Okta, полученный из домена приложения OIDC;

  • quarkus.oidc.client-id: ID клиента для приложения OIDC;

  • quarkus.oidc.credentials.secret: секрет клиента для приложения OIDC;

  • jhipster.oidc.logout-url: в JHipster браузер будет запускать выход из системы. Серверная сторона должна предоставлять эту информацию (пока её невозможно получить с помощью OIDC-поиска).

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

# OAuth 2.0 and OIDCquarkus.oidc.enabled=truequarkus.oidc.auth-server-url=https://dev-9323263.okta.com/oauth2/defaultquarkus.oidc.client-id=0oaajhdr9q9jxbBM95d6quarkus.oidc.credentials.secret=NEVERSHOWSECRETSquarkus.oidc.application-type=hybridquarkus.oidc.authentication.scopes=profile,address,email,address,phonequarkus.oidc.authentication.cookie-path=/quarkus.oidc.authentication.redirect-path=/login/oauth2/code/oidcquarkus.oidc.authentication.restore-path-after-redirect=falsejhipster.oidc.logout-url=https://dev-9323263.okta.com/oauth2/default/v1/logout

Перезапустите приложение, перейдите по адресу http://localhost:8080. Нажмите sign in (вход) и вы будете перенаправлены на страницу входа Okta.

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

Переход в нативный формат с помощью Quarkus и GraalVM

Заключительным шагом в данной вводной статье будет упаковка приложения Java в виде нативного выполняемого файла (оптимизированного для используемого микропроцессора). И снова JHipster надёжно прикрывает ваши тылы, делая для вас всё необходимое. Просто выполните в Maven команду package с профилем native:

./mvnw package -Pnative -DskipTests

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

[error]: Build step io.quarkus.deployment.pkg.steps.NativeImageBuildStep#build threw an exception: java.lang.RuntimeException: Cannot find the `native-image` in the  GRAALVM_HOME, JAVA_HOME and System PATH. Install it using `gu install native-image`

Самым простым способом решения этой проблемы будет применение SDKMAN для установки Java 11 с GraalVM:

sdk install java 21.0.0.2.r11-grl

Затем выполните gu install native-image:

$ gu install native-imageDownloading: Component catalog from www.graalvm.orgProcessing Component: Native ImageDownloading: Component native-image: Native Image  from github.comInstalling new component: Native Image (org.graalvm.native-image, version 21.0.0.2)

Как только процесс завершится, перезапустите команду package в Maven:

./mvnw package -Pnative -DskipTests

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

  • ознакомиться с проектом JHipster Quarkus Blueprint;

  • исследовать сайт для разработчиков Okta;

  • изучить эти великолепные руководства по Quarkus.

Спустя примерно три минуты нативный выполняемый файл должен быть готов:

Запустите его как нативный выполняемый файл, используя команду target/*runner:

Ваше старое доброе Java-приложение запустится через 1 секунду! Помните, я рассказывал о приросте памяти? Ниже привожу команду, как посмотреть потребление памяти в мегабайтах:

$ ps -o pid,rss,command | grep --color jhipster | awk '{$2=int($2/1024)"M";}{ print;}'30951 46M ./target/jhipster-1.0.0-SNAPSHOT-runner31433 0M grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn --color jhipster

Ваше приложение потребляет менее 50 МБ памяти. Перейдите по адресу http://localhost:8080 и убедитесь, что всё исправно работает. Теперь наслаждайтесь своим успехом!

Дальнейшая разработка с помощью JHipster Quarkus

Надеюсь, вы получили удовольствие от данной вводной статьи, пройдя все этапы создания нативного приложения и применяя для этого Java, Quarkus и JHipster. Не правда ли, впечатляет, как JHipster и Okta CLI делают для вас основную тяжёлую работу?! Вы можете найти пример, созданный в этой вводной статье, на GitHub. Если вы заинтересованы в дополнительном изучении blueprint-схем Quarkus, посмотрите проект generator-jhipster-quarkus, также размещённый на GitHub.

Совсем недавно Java считали медленным языком программирования, а вернее было бы сказать, что медленной была виртуальная машина Java, но это не помешало языку стать одним из самых востребованных по версии TIOBE. Сегодня Java становится всё быстрее, а это значит, что она ещё надолго сохранит способность конкурировать с новыми языками; кроме того, в последнее время наметилась тенденция к упрощению синтаксиса Java. Если вам интересен этот язык и работа с ним в перспективе, то вы можете посмотреть на программу обучения нашего курса по Java, где студенты за 14 месяцев получают всестороннюю подготовку к трудоустройству в качестве Java-разработчика.

Узнайте, как прокачаться и в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Ipipou больше чем просто нешифрованный туннель

07.10.2020 18:18:13 | Автор: admin
Что мы говорим богу IPv6?

IPv6? Not today

Верно, и богу шифрования сегодня скажем то же.

Здесь будет о нешифрованном IPv4 туннеле, но не о тёплом ламповом, а о модерновом светодиодном. А ещё тут мелькают сырые сокеты, и идёт работа с пакетами в пространстве пользователя.

Есть N протоколов туннелирования на любой вкус и цвет:

  • стильный, модный, молодёжный WireGuard
  • мультифункциональные, как швейцарские ножи, OpenVPN и SSH
  • старый и не злой GRE
  • максимально простой, шустрый, совсем не шифрованный IPIP
  • активно развивающийся GENEVE
  • множество других.

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

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

Исследуя различные протоколы туннелирования внимание моего внутреннего перфекциониста раз за разом привлекал IPIP из-за его минимальных накладных расходов. Но у него есть полтора существенных недостатка для моих задач:

  • он требует публичные IP на обеих сторонах,
  • и никакой тебе аутентификации.

Поэтому перфекционист загонялся обратно в тёмный угол черепной коробки, или где он там сидит.

И вот как-то раз читая статьи по нативно поддерживаемым туннелям в Linux наткнулся на FOU (Foo-over-UDP), т.е. что-попало, завёрнутое в UDP. Пока из чего-попало поддерживаются только IPIP и GUE (Generic UDP Encapsulation).

Вот она серебряная пуля! Мне и простого IPIP за глаза. думал я.

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

Для решения этой полуторной проблемы и родилась утилита ipipou. В ней реализован самопальный механизм аутентификации удалённого хоста, при этом не нарушая работы ядрёного FOU, который будет шустро и эффективно обрабатывать пакеты в пространстве ядра.

Не нужон твой скрипт!


Ок, если тебе известны публичные порт и IP клиента (например за ним все свои, куда попало не ходют, NAT пытается мапить порты 1-в-1), можешь создать IPIP-over-FOU туннель следующими командами, без всяких скриптов.

на сервере:
# Подгрузить модуль ядра FOUmodprobe fou# Создать IPIP туннель с инкапсуляцией в FOU.# Модуль ipip подгрузится автоматически.ip link add name ipipou0 type ipip \    remote 198.51.100.2 local 203.0.113.1 \    encap fou encap-sport 10000 encap-dport 20001 \    mode ipip dev eth0# Добавить порт на котором будет слушать FOU для этого туннеляip fou add port 10000 ipproto 4 local 203.0.113.1 dev eth0# Назначить IP адрес туннелюip address add 172.28.0.0 peer 172.28.0.1 dev ipipou0# Поднять туннельip link set ipipou0 up

на клиенте:
modprobe fouip link add name ipipou1 type ipip \    remote 203.0.113.1 local 192.168.0.2 \    encap fou encap-sport 10001 encap-dport 10000 encap-csum \    mode ipip dev eth0# Опции local, peer, peer_port, dev могут не поддерживаться старыми ядрами, можно их опустить.# peer и peer_port используются для создания соединения сразу при создании FOU-listener-а.ip fou add port 10001 ipproto 4 local 192.168.0.2 peer 203.0.113.1 peer_port 10000 dev eth0ip address add 172.28.0.1 peer 172.28.0.0 dev ipipou1ip link set ipipou1 up

где
  • ipipou* имя локального туннельного сетевого интерфейса
  • 203.0.113.1 публичный IP сервера
  • 198.51.100.2 публичный IP клиента
  • 192.168.0.2 IP клиента, назначенный интерфейсу eth0
  • 10001 локальный порт клиента для FOU
  • 20001 публичный порт клиента для FOU
  • 10000 публичный порт сервера для FOU
  • encap-csum опция для добавления контрольной суммы UDP в инкапсулированные UDP пакеты; можно заменить на noencap-csum, чтоб не считать, целостность и так контролируется внешним слоем инкапсуляции (пока пакет находится внутри туннеля)
  • eth0 локальный интерфейс к которому будет привязан ipip туннель
  • 172.28.0.1 IP туннельного интерфейса клиента (приватный)
  • 172.28.0.0 IP туннельного интерфейса сервера (приватный)

Пока живо UDP-соединение, туннель будет в работоспособном состоянии, а как порвётся то, как повезёт если IP: порт клиента останутся прежними будет жить, изменятся порвётся.

Вертать всё взад проще всего выгрузив модули ядра: modprobe -r fou ipip

Даже если аутентификация не требуется публичные IP и порт клиента не всегда известны и часто непредсказуемы или изменчивы (в зависимости от типа NAT). Если опустить encap-dport на стороне сервера, туннель не заработает, не настолько он умный, чтоб брать удалённый порт соединения. В этом случае ipipou тоже может помочь, ну или WireGuard и иже с ним тебе в помощь.

Как это работает?


Клиент (что обычно за NAT-ом) поднимает туннель (как в примере выше), и шлёт пакет с аутентификацией на сервер, чтобы тот настроил туннель со своей стороны. В зависимости от настроек это может быть пустой пакет (просто чтобы сервер увидел публичные IP: порт соединения), или с данными по которым сервер сможет идентифицировать клиента. Данные могут быть простой парольной фразой открытым текстом (в голову приходит аналогия с HTTP Basic Auth) или подписанные приватным ключом специально оформленные данные (по аналогии с HTTP Digest Auth только посильнее, см. функцию client_auth в коде).

На сервере (сторона с публичным IP) при запуске ipipou создаёт обработчик очереди nfqueue и настраивает netfilter так, чтоб нужные пакеты направлялись куда следует: пакеты инициализирующие соединение в очередь nfqueue, а [почти] все остальные прямиком в listener FOU.

Кто не в теме, nfqueue (или NetfilterQueue) это такая специальная штука для дилетантов, не умеющих разрабатывать модули ядра, которая средствами netfilter (nftables/iptables) позволяет перенаправлять сетевые пакеты в пространство пользователя и обрабатывать их там примитивными подручными средствами: модифицировать (опционально) и отдавать обратно ядру, или отбрасывать.

Для некоторых языков программирования есть биндинги для работы с nfqueue, для bash не нашлось (хех, не удивительно), пришлось использовать python: ipipou использует NetfilterQueue.

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

Рука об руку с nfqueue работают сырые сокеты (raw sockets), например когда туннель уже настроен, и FOU слушает на нужном порту, обычным способом отправить пакет с этого же порта не получится занято, зато можно взять и запулить произвольно сгенерированный пакет прямо в сетевой интерфейс используя сырой сокет, хоть над генерацией такого пакета и придётся повозиться чуть больше. Так и создаются в ipipou пакеты с аутентификацией.

Так как ipipou обрабатывает только первые пакеты из соединения (ну и те, которые успели просочиться в очередь до установки соединения) производительность почти не страдает.

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

У обычного IPIP-over-FOU есть ещё одна проблема при работе с NAT нельзя создать два IPIP туннеля инкапсулированных в UDP с одинаковыми IP, ибо модули FOU и IPIP достаточно изолированы друг от друга. Т.е. пара клиентов за одним публичным IP не сможет одновременно подключиться к одному серверу таким способом. В будущем, возможно, её решат на уровне ядра, но это не точно. А пока проблемы NAT-а можно решить NAT-ом если случается так, что пара IP адресов уже занята другим туннелем, ipipou сделает NAT с публичного на альтернативный приватный IP, вуаля! можно создавать туннели пока порты не закончатся.

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

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

К слову сказать инкапсуляция в UDP очень хорошо себя зарекомендовала. По сравнению с инкапсуляцией поверх IP она гораздо стабильнее и чаще быстрее несмотря на дополнительные накладные расходы на заголовок UDP. Это связано с тем, что в Интернете бльшая часть хостов сносно работает только с тремя наиболее популярными протоколами: TCP, UDP, ICMP. Ощутимая часть может вообще отбрасывать всё остальное, или обрабатывать медленнее, ибо оптимизирована только под эти три.

Например, поэтому QUICK, на базе которого создан HTTP/3, создавался именно поверх UDP, а не поверх IP.

Ну да хватит слов, пора посмотреть как это работает в реальном мире.

Батл


Для эмуляции реального мира используется iperf3. По степени приближённости к реальности это примерно как эмуляция реального мира в Майнкрафте, но пока сойдёт.

В состязании участвуют:
  • эталонный основной канал
  • герой этой статьи ipipou
  • OpenVPN с аутентификацией, но без шифрования
  • OpenVPN в режиме всё включено
  • WireGuard без PresharedKey, с MTU=1440 (ибо IPv4-only)

Технические данные для гиков
Метрики снимаются такими командами

на клиенте:

UDP
CPULOG=NAME.udp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -c SERVER_IP -4 -t 60 -f m -i 10 -B LOCAL_IP -P 2 -u -b 12M; tail -1 "$CPULOG"# Где "-b 12M" это пропускная способность основного канала, делённая на число потоков "-P", чтобы лишние пакеты не плодить и не портить производительность.

TCP
CPULOG=NAME.tcp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -c SERVER_IP -4 -t 60 -f m -i 10 -B LOCAL_IP -P 2; tail -1 "$CPULOG"

ICMP latency
ping -c 10 SERVER_IP | tail -1

на сервере (запускается одновременно с клиентом):

UDP
CPULOG=NAME.udp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -s -i 10 -f m -1; tail -1 "$CPULOG"

TCP
CPULOG=NAME.tcp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -s -i 10 -f m -1; tail -1 "$CPULOG"

Конфигурация туннелей


ipipou
сервер
/etc/ipipou/server.conf:
servernumber 0fou-dev eth0fou-local-port 10000tunl-ip 172.28.0.0auth-remote-pubkey-b64 eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI=auth-secret topsecretauth-lifetime 3600reply-on-auth-okverb 3

systemctl start ipipou@server

клиент
/etc/ipipou/client.conf:
clientnumber 0fou-local @eth0fou-remote SERVER_IP:10000tunl-ip 172.28.0.1# pubkey of auth-key-b64: eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI=auth-key-b64 RuBZkT23na2Q4QH1xfmZCfRgSgPt5s362UPAFbecTso=auth-secret topsecretkeepalive 27verb 3

systemctl start ipipou@client

openvpn (без шифрования, с аутентификацией)
сервер
openvpn --genkey --secret ovpn.key  # Затем надо передать ovpn.key клиентуopenvpn --dev tun1 --local SERVER_IP --port 2000 --ifconfig 172.16.17.1 172.16.17.2 --cipher none --auth SHA1 --ncp-disable --secret ovpn.key

клиент
openvpn --dev tun1 --local LOCAL_IP --remote SERVER_IP --port 2000 --ifconfig 172.16.17.2 172.16.17.1 --cipher none --auth SHA1 --ncp-disable --secret ovpn.key

openvpn (c шифрованием, аутентификацией, через UDP, всё как положено)
Настроено используя openvpn-manage

wireguard
сервер
/etc/wireguard/server.conf:
[Interface]Address=172.31.192.1/18ListenPort=51820PrivateKey=aMAG31yjt85zsVC5hn5jMskuFdF8C/LFSRYnhRGSKUQ=MTU=1440[Peer]PublicKey=LyhhEIjVQPVmr/sJNdSRqTjxibsfDZ15sDuhvAQ3hVM=AllowedIPs=172.31.192.2/32

systemctl start wg-quick@server

клиент
/etc/wireguard/client.conf:
[Interface]Address=172.31.192.2/18PrivateKey=uCluH7q2Hip5lLRSsVHc38nGKUGpZIUwGO/7k+6Ye3I=MTU=1440[Peer]PublicKey=DjJRmGvhl6DWuSf1fldxNRBvqa701c0Sc7OpRr4gPXk=AllowedIPs=172.31.192.1/32Endpoint=SERVER_IP:51820

systemctl start wg-quick@client

Результаты


Сырая страшненькая табличка
Загрузка CPU сервера не очень показательна, т.к. там крутится много других сервисов иногда они жрут ресурсы:

proto bandwidth[Mbps] CPU_idle_client[%] CPU_idle_server[%]# 20 Mbps канал с микрокомпьютера (4 core) до VPS (1 core) через Атлантику# pureUDP 20.4      99.80 93.34TCP 19.2      99.67 96.68ICMP latency min/avg/max/mdev = 198.838/198.997/199.360/0.372 ms# ipipouUDP 19.8      98.45 99.47TCP 18.8      99.56 96.75ICMP latency min/avg/max/mdev = 199.562/208.919/220.222/7.905 ms# openvpn (auth only, no encryption)UDP 19.3      99.89 72.90TCP 16.1      95.95 88.46ICMP latency min/avg/max/mdev = 191.631/193.538/198.724/2.520 ms# openvpn (auth only, no encryption)UDP 19.6      99.75 72.35TCP 17.0      94.47 87.99ICMP latency min/avg/max/mdev = 202.168/202.377/202.900/0.451 ms# wireguardUDP 19.3      91.60 94.78TCP 17.2      96.76 92.87ICMP latency min/avg/max/mdev = 217.925/223.601/230.696/3.266 ms## около-1Gbps канал между VPS Европы и США (1 core)# pureUDP 729      73.40 39.93TCP 363      96.95 90.40ICMP latency min/avg/max/mdev = 106.867/106.994/107.126/0.066 ms# ipipouUDP 714      63.10 23.53TCP 431      95.65 64.56ICMP latency min/avg/max/mdev = 107.444/107.523/107.648/0.058 ms# openvpn (auth only, no encryption)UDP 193      17.51  1.62TCP  12      95.45 92.80ICMP latency min/avg/max/mdev = 107.191/107.334/107.559/0.116 ms# wireguardUDP 629      22.26  2.62TCP 198      77.40 55.98ICMP latency min/avg/max/mdev = 107.616/107.788/108.038/0.128 ms


канал на 20 Mbps

сравнение пропускной способности на 20 Mbps

сравнение задержки на 20 Mbps

канал на 1 оптимистичный Gbps

сравнение пропускной способности на 1 Gbps

сравнение эффективности использования CPU: Mbps/CPU_usage

Во всех случаях ipipou довольно близок по показателям к базовому каналу, и это прекрасно!

Нешифрованный туннель openvpn повёл себя довольно странно в обоих случаях.

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

Да пребудет с нами IPv6 и NetPrickle!
Подробнее..

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

30.04.2021 12:16:20 | Автор: admin

В digital-агентстве Convergent, где я работаю, в потоке множество проектов, и у каждого из них может быть собственная админка. Есть несколько окружений (дев, стейдж, лайв). А ещё есть разные внутрикорпоративные сервисы (как собственной разработки, так и сторонние вроде Redmine или Mattermost), которыми ежедневно пользуются сотрудники.

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

В данной статье я хочу поделиться опытом создания собственной внутренней системы аутентификации на основе OpenResty, а также спецификации OAuth2. В качестве основного языка программирования мы используем PHP, а фреймворк Yii 2.

Суммирую необходимый функционал:

  • Единое место управления всеми доступами. Здесь происходит выдача и отзыв доступов в административные панели сайтов и списки доменов;

  • По умолчанию весь доступ запрещён, если не указано обратное (доступ к любым доменам контролируется с помощью OpenResty);

  • Аутентификация для сотрудников;

  • Аутентификация для клиентов.

Закрытый доступ к сайтам и инфраструктуре

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

Упрощенная схема взаимодействия между пользователями и серверамиУпрощенная схема взаимодействия между пользователями и серверами

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

Фронт-контроллером в данном случае выступает OpenResty это модифицированная версия nginx, которая в т. ч. поддерживает из коробки язык Lua. На нём я написал прослойку, через которую проходят все HTTP(s)-запросы.

Вот так может выглядеть код скрипта аунтентификации (в упрощенном варианте):

auth.lua
function authenticationPrompt()    ngx.header.www_authenticate = 'Basic realm="Restricted by OpenResty"'    ngx.exit(401)endfunction hasAccessByIp()    local ip = ngx.var.remote_addr    local domain = ngx.var.host    local port = ngx.var.server_port    local res, err = httpc:request_uri(os.getenv("AUTH_API_URL") .. "/ip.php", {        method = "GET",        query = "ip=" .. ip .. '&domain=' .. domain .. '&port=' .. port,        headers = {          ["Content-Type"] = "application/x-www-form-urlencoded",        },        keepalive_timeout = 60000,        keepalive_pool = 10,        ssl_verify = false    })    if res ~= nil then        if (res.status == 200) then            session.data.domains[domain] = true            session:save()            return true        elseif (res.status == 403) then            return false        else            session:close()            ngx.say("Server error: " .. res.body)            ngx.exit(500)        end    else        session:close()        ngx.say("Server error: " .. err)        ngx.exit(500)    endendfunction hasAccessByLogin()    local header = ngx.var.http_authorization    local domain = ngx.var.host    local port = ngx.var.server_port    if (header ~= nil) then        header = ngx.decode_base64(header:sub(header:find(' ') + 1))        login, password = header:match("([^,]+):([^,]+)")        if login == nil then            login = ""        end        if password == nil then            password = ""        end        local res, err = httpc:request_uri(os.getenv("AUTH_API_URL") .. '/login.php', {            method = "POST",            body = "username=" .. login .. '&password=' .. password .. '&domain=' .. domain .. '&port=' .. port,            headers = {              ["Content-Type"] = "application/x-www-form-urlencoded",            },            keepalive_timeout = 60000,            keepalive_pool = 10,            ssl_verify = false        })        if res ~= nil then            if (res.status == 200) then                session.data.domains[domain] = true                session:save()                return true            elseif (res.status == 403) then                return false            else                session:close()                ngx.say("Server error: " .. res.body)                ngx.exit(500)            end        else            session:close()            ngx.say("Server error: " .. err)            ngx.exit(500)        end    else        return false    endendos = require("os")http = require "resty.http"httpc = http.new()session = require "resty.session".new()session:start()if (session.data.domains == nil) then    session.data.domains = {}endlocal domain = ngx.var.hostif session.data.domains[domain] == nil then    if (not hasAccessByIp() and not hasAccessByLogin()) then        session:close()        authenticationPrompt()    else        session:close()    endelse    session:close()end

Алгоритм работы скрипта довольно простой:

  • Поступает HTTP-запрос от пользователя;

  • OpenResty запускает скрипт auth.lua;

  • Скрипт определяет запрашиваемый домен и отправляет два запроса на внешний бэкенд;

  • Первый на проверку IP-адреса пользователя в базу;

  • Если IP отсутствует, выводит браузерное окно для ввода логина и пароля, отправляет второй запрос на проверку доступа;

  • В любой другой ситуации выводит окно Вход.

На GitHub я выложил рабочий пример, который можно быстро развернуть с помощью Docker.

Немного расскажу о том, как выглядит управление в нашей системе.

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

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

Для клиентов же создаются простые доступы по паре логин-пароль. Такие доступы ограничиваются в пределах определенных доменных адресов.

Управление доступами по паролю и по IP-адресуУправление доступами по паролю и по IP-адресу

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

Форма аутентификации для сотрудниковФорма аутентификации для сотрудников

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

Двухфакторная аутентификация

Для обеспечения двухфакторной аутентификации для сотрудников решено было добавить Google Authenticator. Такой механизм защиты позволяет больше обезопасить себя от утечки доступов. Для PHP есть готовая библиотека sonata-project/GoogleAuthenticator. Пример интеграции можно посмотреть здесь.

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

OAuth и OpenID

Третье, и не менее важное для нас, создание OAuth-сервера. За основу мы взяли модуль thephpleague/oauth2-server. Для Yii 2 готового решения не было, поэтому написали собственную имплементацию сервера. OAuth2 достаточно обширная тема, расписывать её работу в данной статье не буду. Библиотека имеет хорошую документацию. Также она поддерживает различные фреймворки, включая Laravel и Symfony.

Таким образом, любой сторонний сервис, который поддерживает кастомные OAuth2 конфигурации, достаточно просто подключается к нашей системе. Значимой фишкой такой интеграции стало подключение нашего ID к Mattermost. Последний в бесплатной версии поддерживает только аутентификацию с помощью GitLab, которую удалось эмулировать через наш сервис.

Также для всех наших проектов на Yii был разработан модуль для подключения ID. Это позволило вынести всё управление доступами в админпанели для сотрудников в централизованное место. Кстати, если интересно, я писал статью о модульном подходе, который мы применили в нашем digital-агентстве.

Заключение

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

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

Ссылки по теме

Подробнее..

Spring Security пример REST-сервиса с авторизацией по протоколу OAuth2 через BitBucket и JWT

17.11.2020 00:09:32 | Автор: admin
В предыдущей статье мы разработали простое защищенное веб приложение, в котором для аутентификации пользователей использовался протокол OAuth2 с Bitbucket в качестве сервера авторизации. Кому-то такая связка может показаться странной, но представьте, что мы разрабатываем CI (Continuous Integration) сервер и хотели бы иметь доступ к ресурсам пользователя в системе контроля версий. Например, по такому же принципу работает довольно известная CI платформа drone.io.

В предыдущем примере для авторизации запросов к серверу использовалась HTTP-сессия (и куки). Однако для реализации REST-сервиса данный способ авторизации не подходит, поскольку одним из требований REST архитектуры является отсутсвие состояния. В данной статье мы реализуем REST-сервис, авторизация запросов к которому будет осуществляться с помощью токена доступа (access token).

Немного теории


Аутентификация это процесс проверки учётных данных пользователя (логин/пароль). Проверка подлинности пользователя осуществляется путём сравнения введённого им логина/пароля с сохраненными данными.
Авторизация это проверка прав пользователя на доступ к определенным ресурсам. Авторизация выполняется непосредственно при обращении пользователя к ресурсу.

Рассмотрим порядок работы двух вышеупомянутых способов авторизации запросов.
Авторизация запросов с помощью HTTP-сессии:
  • Пользователь проходит аутентификацию любым из способов.
  • На сервере создается HTTP-сессия и куки JSESSIONID, хранящий идентификатор сессии.
  • Куки JSESSIONID передается на клиент и сохраняется в браузере.
  • С каждым последующим запросом на сервер отправляется куки JSESSIONID.
  • Сервер находит соответствующую HTTP-сессию с информацией о текущем пользователе и определяет имеет ли пользователь права на выполнение данного вызова.
  • Для выполнения выхода из приложения необходимо удалить с сервера HTTP-сессию.


Авторизация запросов с помощью токена доступа:
  • Пользователь проходит аутентификацию любым из способов.
  • Сервер создает токен доступа, подписанный секретным ключом, а затем отправляет его клиенту. Токен содержит идентификатор пользователя и его роли.
  • Токен сохраняется на клиенте и передается на сервер с каждым последующим запросом. Как правило для передачи токена используетя HTTP заголовок Authorization.
  • Сервер сверяет подпись токена, извлекает из него идентификатор пользователя, его роли и определяет имеет ли пользователь права на выполнение данного вызова.
  • Для выполнения выхода из приложения достаточно просто удалить токен на клиенте без необходимости взаимодействия с сервером.


Распространенным форматом токена доступа в настоящее время является JSON Web Token (JWT). Токен в формате JWT содержит три блока, разделенных точками: заголовок (header), набор полей (payload) и сигнатуру (подпись). Первые два блока представлены в JSON-формате и закодированы в формат base64. Набор полей может состоять как из зарезервированных имен (iss, iat, exp), так и произвольных пар имя/значение. Подпись может генерироваться как при помощи симметричных, так и асимметричных алгоритмов шифрования.

Реализация


Мы реализуем REST-сервис, предоставляющий следующее API:
  • GET /auth/login запустить процесс аутентификации пользователя.
  • POST /auth/token запросить новую пару access/refresh токенов.
  • GET /api/repositories получить список Bitbucket репозиториев текущего пользователя.


Высокоуровневая архитектура приложения.

Заметим, что поскольку приложение состоит из трех взаимодействующих компонентов, помимо того, что мы выполняем авторизацию запросов клиента к серверу, Bitbucket авторизует запросы сервера к нему. Мы не будем настраивать авторизацию методов по ролям, чтобы не делать пример сложнее. У нас есть только один API метод GET /api/repositories, вызывать который могут только аутентифицированные пользователи. Сервер может выполнять на Bitbucket любые операции, разрешенные при регистрации OAuth клиента.

Процесс регистрации OAuth клиента описан в предыдущей статье.

Для реализации мы будем использовать Spring Boot версии 2.2.2.RELEASE и Spring Security версии 5.2.1.RELEASE.

Переопределим AuthenticationEntryPoint.


В стандартном веб-приложении, когда осуществляется обращение к защищенному ресурсу и в секьюрити контексте отсутствует объект Authentication, Spring Security перенаправляет пользователя на страницу аутентификации. Однако для REST-сервиса более подходящим поведением в этом случае было бы возвращать HTTP статус 401 (UNAUTHORIZED).

RestAuthenticationEntryPoint
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {    @Override    public void commence(            HttpServletRequest request,            HttpServletResponse response,            AuthenticationException authException) throws IOException {        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());    }}


Создадим login endpoint.


Для аутентификации пользователя мы по-прежнему используем OAuth2 с типом авторизации Authorization Code. Однако на предыдущем шаге мы заменили стандартный AuthenticationEntryPoint своей реализацией, поэтому нам нужен явный способ запустить процесс аутентификации. При отправке GET запроса по адресу /auth/login мы перенаправим пользователя на страницу аутентификации Bitbucket. Параметром этого метода будет URL обратного вызова, по которому мы возвратим токен доступа после успешной аутентификации.

Login endpoint
@Path("/auth")public class AuthEndpoint extends EndpointBase {...    @GET    @Path("/login")    public Response authorize(@QueryParam(REDIRECT_URI) String redirectUri) {        String authUri = "/oauth2/authorization/bitbucket";        UriComponentsBuilder builder = fromPath(authUri).queryParam(REDIRECT_URI, redirectUri);        return handle(() -> temporaryRedirect(builder.build().toUri()).build());    }}


Переопределим AuthenticationSuccessHandler.


AuthenticationSuccessHandler вызывается после успешной аутентификации. Сгенерируем тут токен доступа, refresh токен и выполним редирект по адресу обратного вызова, который был передан в начале процесса аутентификации. Токен доступа вернем параметром GET запроса, а refresh токен в httpOnly куке. Что такое refresh токен разберем позже.

ExampleAuthenticationSuccessHandler
public class ExampleAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {    private final TokenService tokenService;    private final AuthProperties authProperties;    private final HttpCookieOAuth2AuthorizationRequestRepository authorizationRequestRepository;    public ExampleAuthenticationSuccessHandler(            TokenService tokenService,            AuthProperties authProperties,            HttpCookieOAuth2AuthorizationRequestRepository authorizationRequestRepository) {        this.tokenService = requireNonNull(tokenService);        this.authProperties = requireNonNull(authProperties);        this.authorizationRequestRepository = requireNonNull(authorizationRequestRepository);    }    @Override    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {        log.info("Logged in user {}", authentication.getPrincipal());        super.onAuthenticationSuccess(request, response, authentication);    }    @Override    protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {        Optional<String> redirectUri = getCookie(request, REDIRECT_URI).map(Cookie::getValue);        if (redirectUri.isPresent() && !isAuthorizedRedirectUri(redirectUri.get())) {            throw new BadRequestException("Received unauthorized redirect URI.");        }        return UriComponentsBuilder.fromUriString(redirectUri.orElse(getDefaultTargetUrl()))                .queryParam("token", tokenService.newAccessToken(toUserContext(authentication)))                .build().toUriString();    }    @Override    protected void handle(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {        redirectToTargetUrl(request, response, authentication);    }    private boolean isAuthorizedRedirectUri(String uri) {        URI clientRedirectUri = URI.create(uri);        return authProperties.getAuthorizedRedirectUris()                .stream()                .anyMatch(authorizedRedirectUri -> {                    // Only validate host and port. Let the clients use different paths if they want to.                    URI authorizedURI = URI.create(authorizedRedirectUri);                    return authorizedURI.getHost().equalsIgnoreCase(clientRedirectUri.getHost())                            && authorizedURI.getPort() == clientRedirectUri.getPort();                });    }    private TokenService.UserContext toUserContext(Authentication authentication) {        ExampleOAuth2User principal = (ExampleOAuth2User) authentication.getPrincipal();        return TokenService.UserContext.builder()                .login(principal.getName())                .name(principal.getFullName())                .build();    }    private void addRefreshTokenCookie(HttpServletResponse response, Authentication authentication) {        RefreshToken token = tokenService.newRefreshToken(toUserContext(authentication));        addCookie(response, REFRESH_TOKEN, token.getId(), (int) token.getValiditySeconds());    }    private void redirectToTargetUrl(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {        String targetUrl = determineTargetUrl(request, response, authentication);        if (response.isCommitted()) {            logger.debug("Response has already been committed. Unable to redirect to " + targetUrl);            return;        }        addRefreshTokenCookie(response, authentication);        authorizationRequestRepository.removeAuthorizationRequestCookies(request, response);        getRedirectStrategy().sendRedirect(request, response, targetUrl);    }}


Переопределим AuthenticationFailureHandler.


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

ExampleAuthenticationFailureHandler
public class ExampleAuthenticationFailureHandler implements AuthenticationFailureHandler {    private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();    private final HttpCookieOAuth2AuthorizationRequestRepository authorizationRequestRepository;    public ExampleAuthenticationFailureHandler(            HttpCookieOAuth2AuthorizationRequestRepository authorizationRequestRepository) {        this.authorizationRequestRepository = requireNonNull(authorizationRequestRepository);    }    @Override    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException {        String targetUrl = getFailureUrl(request, exception);        authorizationRequestRepository.removeAuthorizationRequestCookies(request, response);        redirectStrategy.sendRedirect(request, response, targetUrl);    }    private String getFailureUrl(HttpServletRequest request, AuthenticationException exception) {        String targetUrl = getCookie(request, Cookies.REDIRECT_URI)                .map(Cookie::getValue)                .orElse(("/"));        return UriComponentsBuilder.fromUriString(targetUrl)                .queryParam("error", exception.getLocalizedMessage())                .build().toUriString();    }}


Создадим TokenAuthenticationFilter.


Задача этого фильтра извлечь токен доступа из заголовка Authorization в случае его наличия, провалидировать его и инициализировать секьюрити контекст.

TokenAuthenticationFilter
public class TokenAuthenticationFilter extends OncePerRequestFilter {    private final UserService userService;    private final TokenService tokenService;    public TokenAuthenticationFilter(            UserService userService, TokenService tokenService) {        this.userService = requireNonNull(userService);        this.tokenService = requireNonNull(tokenService);    }    @Override    protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain chain) throws ServletException, IOException {        try {            Optional<String> jwtOpt = getJwtFromRequest(request);            if (jwtOpt.isPresent()) {                String jwt = jwtOpt.get();                if (isNotEmpty(jwt) && tokenService.isValidAccessToken(jwt)) {                    String login = tokenService.getUsername(jwt);                    Optional<User> userOpt = userService.findByLogin(login);                    if (userOpt.isPresent()) {                        User user = userOpt.get();                        ExampleOAuth2User oAuth2User = new ExampleOAuth2User(user);                        OAuth2AuthenticationToken authentication = new OAuth2AuthenticationToken(oAuth2User, oAuth2User.getAuthorities(), oAuth2User.getProvider());                        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));                        SecurityContextHolder.getContext().setAuthentication(authentication);                    }                }            }        } catch (Exception e) {            logger.error("Could not set user authentication in security context", e);        }        chain.doFilter(request, response);    }    private Optional<String> getJwtFromRequest(HttpServletRequest request) {        String token = request.getHeader(AUTHORIZATION);        if (isNotEmpty(token) && token.startsWith("Bearer ")) {            token = token.substring(7);        }        return Optional.ofNullable(token);    }}


Создадим refresh token endpoint.


В целях безопасности время жизни токена доступа обычно делают небольшим. Тогда в случае его кражи злоумышленник не сможет пользоваться им бесконечно долго. Чтобы не заставлять пользователя выполнять вход в приложение снова и снова используется refresh токен. Он выдается сервером после успешной аутентификации вместе с токеном доступа и имеет большее время жизни. Используя его можно запросить новую пару токенов. Refresh токен рекомендуют хранить в httpOnly куке.

Refresh token endpoint
@Path("/auth")public class AuthEndpoint extends EndpointBase {...    @POST    @Path("/token")    @Produces(APPLICATION_JSON)    public Response refreshToken(@CookieParam(REFRESH_TOKEN) String refreshToken) {        return handle(() -> {            if (refreshToken == null) {                throw new InvalidTokenException("Refresh token was not provided.");            }            RefreshToken oldRefreshToken = tokenService.findRefreshToken(refreshToken);            if (oldRefreshToken == null || !tokenService.isValidRefreshToken(oldRefreshToken)) {                throw new InvalidTokenException("Refresh token is not valid or expired.");            }            Map<String, String> result = new HashMap<>();            result.put("token", tokenService.newAccessToken(of(oldRefreshToken.getUser())));            RefreshToken newRefreshToken = newRefreshTokenFor(oldRefreshToken.getUser());            return Response.ok(result).cookie(createRefreshTokenCookie(newRefreshToken)).build();        });    }}


Переопределим AuthorizationRequestRepository.


Spring Security использует объект AuthorizationRequestRepository для хранения объектов OAuth2AuthorizationRequest на время процесса аутентификации. Реализацией по умолчанию является класс HttpSessionOAuth2AuthorizationRequestRepository, который использует HTTP-сессию в качестве хранилища. Т.к. наш сервис не должен хранить состояние, эта реализация нам не подходит. Реализуем свой класс, который будет использовать HTTP cookies.

HttpCookieOAuth2AuthorizationRequestRepository
public class HttpCookieOAuth2AuthorizationRequestRepository implements AuthorizationRequestRepository<OAuth2AuthorizationRequest> {    private static final int COOKIE_EXPIRE_SECONDS = 180;    private static final String OAUTH2_AUTHORIZATION_REQUEST_COOKIE_NAME = "OAUTH2-AUTH-REQUEST";    @Override    public OAuth2AuthorizationRequest loadAuthorizationRequest(HttpServletRequest request) {        return getCookie(request, OAUTH2_AUTHORIZATION_REQUEST_COOKIE_NAME)                .map(cookie -> deserialize(cookie, OAuth2AuthorizationRequest.class))                .orElse(null);    }    @Override    public void saveAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest, HttpServletRequest request, HttpServletResponse response) {        if (authorizationRequest == null) {            removeAuthorizationRequestCookies(request, response);            return;        }        addCookie(response, OAUTH2_AUTHORIZATION_REQUEST_COOKIE_NAME, serialize(authorizationRequest), COOKIE_EXPIRE_SECONDS);        String redirectUriAfterLogin = request.getParameter(QueryParams.REDIRECT_URI);        if (isNotBlank(redirectUriAfterLogin)) {            addCookie(response, REDIRECT_URI, redirectUriAfterLogin, COOKIE_EXPIRE_SECONDS);        }    }    @Override    public OAuth2AuthorizationRequest removeAuthorizationRequest(HttpServletRequest request) {        return loadAuthorizationRequest(request);    }    public void removeAuthorizationRequestCookies(HttpServletRequest request, HttpServletResponse response) {        deleteCookie(request, response, OAUTH2_AUTHORIZATION_REQUEST_COOKIE_NAME);        deleteCookie(request, response, REDIRECT_URI);    }    private static String serialize(Object object) {        return Base64.getUrlEncoder().encodeToString(SerializationUtils.serialize(object));    }    @SuppressWarnings("SameParameterValue")    private static <T> T deserialize(Cookie cookie, Class<T> clazz) {        return clazz.cast(SerializationUtils.deserialize(Base64.getUrlDecoder().decode(cookie.getValue())));    }}


Настроим Spring Security.


Соберем все проделанное выше вместе и настроим Spring Security.

WebSecurityConfig
@Configuration@EnableWebSecuritypublic static class WebSecurityConfig extends WebSecurityConfigurerAdapter {    private final ExampleOAuth2UserService userService;    private final TokenAuthenticationFilter tokenAuthenticationFilter;    private final AuthenticationFailureHandler authenticationFailureHandler;    private final AuthenticationSuccessHandler authenticationSuccessHandler;    private final HttpCookieOAuth2AuthorizationRequestRepository authorizationRequestRepository;    @Autowired    public WebSecurityConfig(            ExampleOAuth2UserService userService,            TokenAuthenticationFilter tokenAuthenticationFilter,            AuthenticationFailureHandler authenticationFailureHandler,            AuthenticationSuccessHandler authenticationSuccessHandler,            HttpCookieOAuth2AuthorizationRequestRepository authorizationRequestRepository) {        this.userService = userService;        this.tokenAuthenticationFilter = tokenAuthenticationFilter;        this.authenticationFailureHandler = authenticationFailureHandler;        this.authenticationSuccessHandler = authenticationSuccessHandler;        this.authorizationRequestRepository = authorizationRequestRepository;    }    @Override    protected void configure(HttpSecurity http) throws Exception {        http                .cors().and()                .csrf().disable()                .formLogin().disable()                .httpBasic().disable()                .sessionManagement(sm -> sm.sessionCreationPolicy(STATELESS))                .exceptionHandling(eh -> eh                        .authenticationEntryPoint(new RestAuthenticationEntryPoint())                )                .authorizeRequests(authorizeRequests -> authorizeRequests                        .antMatchers("/auth/**").permitAll()                        .anyRequest().authenticated()                )                .oauth2Login(oauth2Login -> oauth2Login                        .failureHandler(authenticationFailureHandler)                        .successHandler(authenticationSuccessHandler)                        .userInfoEndpoint(userInfoEndpoint -> userInfoEndpoint.userService(userService))                        .authorizationEndpoint(authEndpoint -> authEndpoint.authorizationRequestRepository(authorizationRequestRepository))                );        http.addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);    }}


Создадим repositories endpoint.


То ради чего и нужна была аутентификация через OAuth2 и Bitbucket возможность использовать Bitbucket API для доступа к своим ресурсам. Используем Bitbucket repositories API для получения списка репозиториев текущего пользователя.

Repositories endpoint
@Path("/api")public class ApiEndpoint extends EndpointBase {    @Autowired    private BitbucketService bitbucketService;    @GET    @Path("/repositories")    @Produces(APPLICATION_JSON)    public List<Repository> getRepositories() {        return handle(bitbucketService::getRepositories);    }}public class BitbucketServiceImpl implements BitbucketService {    private static final String BASE_URL = "https://api.bitbucket.org";    private final Supplier<RestTemplate> restTemplate;    public BitbucketServiceImpl(Supplier<RestTemplate> restTemplate) {        this.restTemplate = restTemplate;    }    @Override    public List<Repository> getRepositories() {        UriComponentsBuilder uriBuilder = fromHttpUrl(format("%s/2.0/repositories", BASE_URL));        uriBuilder.queryParam("role", "member");        ResponseEntity<BitbucketRepositoriesResponse> response = restTemplate.get().exchange(                uriBuilder.toUriString(),                HttpMethod.GET,                new HttpEntity<>(new HttpHeadersBuilder()                        .acceptJson()                        .build()),                BitbucketRepositoriesResponse.class);        BitbucketRepositoriesResponse body = response.getBody();        return body == null ? emptyList() : extractRepositories(body);    }    private List<Repository> extractRepositories(BitbucketRepositoriesResponse response) {        return response.getValues() == null                ? emptyList()                : response.getValues().stream().map(BitbucketServiceImpl.this::convertRepository).collect(toList());    }    private Repository convertRepository(BitbucketRepository bbRepo) {        Repository repo = new Repository();        repo.setId(bbRepo.getUuid());        repo.setFullName(bbRepo.getFullName());        return repo;    }}


Тестирование


Для тестирования нам понадобится небольшой HTTP-сервер, на который будет отправлен токен доступа. Сначала попробуем вызвать repositories endpoint без токена доступа и убедимся, что в этом случае получим ошибку 401. Затем пройдем аутентификацию. Для этого запустим сервер и перейдем в браузере по адресу http://localhost:8080/auth/login. После того как мы введем логин/пароль, клиент получит токен и вызовет repositories endpoint еще раз. Затем будет запрошен новый токен и снова вызван repositories endpoint с новым токеном.

OAuth2JwtExampleClient
public class OAuth2JwtExampleClient {    /**     * Start client, then navigate to http://localhost:8080/auth/login.     */    public static void main(String[] args) throws Exception {        AuthCallbackHandler authEndpoint = new AuthCallbackHandler(8081);        authEndpoint.start(SOCKET_READ_TIMEOUT, true);        HttpResponse response = getRepositories(null);        assert (response.getStatusLine().getStatusCode() == SC_UNAUTHORIZED);        Tokens tokens = authEndpoint.getTokens();        System.out.println("Received tokens: " + tokens);        response = getRepositories(tokens.getAccessToken());        assert (response.getStatusLine().getStatusCode() == SC_OK);        System.out.println("Repositories: " + IOUtils.toString(response.getEntity().getContent(), UTF_8));        // emulate token usage - wait for some time until iat and exp attributes get updated        // otherwise we will receive the same token        Thread.sleep(5000);        tokens = refreshToken(tokens.getRefreshToken());        System.out.println("Refreshed tokens: " + tokens);        // use refreshed token        response = getRepositories(tokens.getAccessToken());        assert (response.getStatusLine().getStatusCode() == SC_OK);    }    private static Tokens refreshToken(String refreshToken) throws IOException {        BasicClientCookie cookie = new BasicClientCookie(REFRESH_TOKEN, refreshToken);        cookie.setPath("/");        cookie.setDomain("localhost");        BasicCookieStore cookieStore = new BasicCookieStore();        cookieStore.addCookie(cookie);        HttpPost request = new HttpPost("http://localhost:8080/auth/token");        request.setHeader(ACCEPT, APPLICATION_JSON.getMimeType());        HttpClient httpClient = HttpClientBuilder.create().setDefaultCookieStore(cookieStore).build();        HttpResponse execute = httpClient.execute(request);        Gson gson = new Gson();        Type type = new TypeToken<Map<String, String>>() {        }.getType();        Map<String, String> response = gson.fromJson(IOUtils.toString(execute.getEntity().getContent(), UTF_8), type);        Cookie refreshTokenCookie = cookieStore.getCookies().stream()                .filter(c -> REFRESH_TOKEN.equals(c.getName()))                .findAny()                .orElseThrow(() -> new IOException("Refresh token cookie not found."));        return Tokens.of(response.get("token"), refreshTokenCookie.getValue());    }    private static HttpResponse getRepositories(String accessToken) throws IOException {        HttpClient httpClient = HttpClientBuilder.create().build();        HttpGet request = new HttpGet("http://localhost:8080/api/repositories");        request.setHeader(ACCEPT, APPLICATION_JSON.getMimeType());        if (accessToken != null) {            request.setHeader(AUTHORIZATION, "Bearer " + accessToken);        }        return httpClient.execute(request);    }}


Консольный вывод клиента.
Received tokens: Tokens(accessToken=eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJldm9sdmVjaS10ZXN0a2l0IiwidXNlcm5hbWUiOiJFdm9sdmVDSSBUZXN0a2l0IiwiaWF0IjoxNjA1NDY2MDMxLCJleHAiOjE2MDU0NjY2MzF9.UuRYMdIxzc8ZFEI2z8fAgLz-LG_gDxaim25pMh9jNrDFK6YkEaDqDO8Huoav5JUB0bJyf1lTB0nNPaLLpOj4hw, refreshToken=BBF6dboG8tB4XozHqmZE5anXMHeNUncTVD8CLv2hkaU2KsfyqitlJpgkV4HrQqPk)Repositories: [{"id":"{c7bb4165-92f1-4621-9039-bb1b6a74488e}","fullName":"test-namespace/test-repository1"},{"id":"{aa149604-c136-41e1-b7bd-3088fb73f1b2}","fullName":"test-namespace/test-repository2"}]Refreshed tokens: Tokens(accessToken=eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJldm9sdmVjaS10ZXN0a2l0IiwidXNlcm5hbWUiOiJFdm9sdmVDSSBUZXN0a2l0IiwiaWF0IjoxNjA1NDY2MDM2LCJleHAiOjE2MDU0NjY2MzZ9.oR2A_9k4fB7qpzxvV5QKY1eU_8aZMYEom-ngc4Kuc5omeGPWyclfqmiyQTpJW_cHOcXbY9S065AE_GKXFMbh_Q, refreshToken=mdc5sgmtiwLD1uryubd2WZNjNzSmc5UGo6JyyzsiYsBgOpeaY3yw3T3l8IKauKYQ)

Исходный код


Полный исходный код рассмотренного приложения находится на Github.

Ссылки



P.S.
Созданный нами REST-сервис работает по протоколу HTTP, чтобы не усложнять пример. Но поскольку токены у нас никак не шифруются, рекомендуется перейти на защищенный канал (HTTPS).
Подробнее..

Перевод Создание API аутентификации с помощью Golang

27.12.2020 12:16:52 | Автор: admin
Небольшая статья для начинающих о том, как создать API аутентификацию с помощью Gо.




Требования


Необходимо установить Go на ваш компьютер.

Приступим к работе


Прежде всего создадим новый проект. Создайте новый файл с именем main.go и введите стартовый код:

package mainimport (  "fmt"  "net/http"  "github.com/gin-gonic/gin")

Методы POST и GET


Чтобы обрабатывать запросы GET и POST, создадим GetMethod и PostMethod:

func PostMethod(c *gin.Context) {  fmt.Println("\napi.go 'PostMethod' called")  message := "PostMethod called"  c.JSON(http.StatusOK, message)}func GetMethod(c *gin.Context) {  fmt.Println("\napi.go 'GetMethod' called")  message := "GetMethod called"  c.JSON(http.StatusOK, message)}

Основная функция


Необходимо создать роутер Gin для обработки всех запросов:

func main() {  router := gin.Default()}

После этого добавим GetMethod и PostMethod:

func main() {  router := gin.Default()router.POST("/", PostMethod)  router.GET("/", GetMethod)}

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

func main() {  router := gin.Default()router.POST("/", PostMethod)  router.GET("/", GetMethod)listenPort := "4000"router.Run(":"+listenPort)}

Теперь запустим код, чтобы проверить, работает ли сервер.

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


Когда базовый веб-сервер настроен, начнем добавлять элементы для API аутентификации.

Начнем с func main():

func main() {  router := gin.Default()subRouterAuthenticated := router.Group("/api/v1/PersonId", gin.BasicAuth(gin.Accounts{    "admin": "adminpass",  }))listenPort := "1357"router.Run(":"+listenPort)}

Теперь передайте query-параметры:

func main() {  router := gin.Default()subRouterAuthenticated := router.Group("/api/v1/PersonId", gin.BasicAuth(gin.Accounts{    "admin": "adminpass",  }))subRouterAuthenticated.GET("/:IdValue", GetMethod)listenPort := "1357"  router.Run(":"+listenPort)}

Настройка GetMethod()


GetMethod() запрашивает и выводит Person IdValue из query-параметра, переданного в URL-адресе API:

func GetMethod(c *gin.Context) {  fmt.Println("\n'GetMethod' called")  IdValue := c.Params.ByName("IdValue")  message := "GetMethod Called With Param: " + IdValue  c.JSON(http.StatusOK, message)ReqPayload := make([]byte, 1024)  ReqPayload, err := c.GetRawData()  if err != nil {        fmt.Println(err)        return  }  fmt.Println("Request Payload Data: ", string(ReqPayload))}

Полный пример:

package mainimport (  "fmt"  "net/http"  "github.com/gin-gonic/gin")func GetMethod(c *gin.Context) {  fmt.Println("\n'GetMethod' called")  IdValue := c.Params.ByName("IdValue")  message := "GetMethod Called With Param: " + IdValue  c.JSON(http.StatusOK, message)ReqPayload := make([]byte, 1024)  ReqPayload, err := c.GetRawData()  if err != nil {        fmt.Println(err)        return  }  fmt.Println("Request Payload Data: ", string(ReqPayload))}func main() {  router := gin.Default()subRouterAuthenticated := router.Group("/api/v1/PersonId", gin.BasicAuth(gin.Accounts{    "admin": "adminpass",  }))subRouterAuthenticated.GET("/:IdValue", GetMethod)listenPort := "1357"    router.Run(":"+listenPort)}

Тестирование с помощью ngrok


Сначала запустим наше приложение на Go:

go run main.go

1. Скачайте ngrok.

2. Распакуйте исполняемый файл ngrok в папку на сервере.

3. Запустите ngrok на порту 1357 (который вы указали в коде):

./ngrok http 1357

Результат:

ngrok by @emmyc (Ctrl+C to quit)
Session Status online
Session Expires 7 hours, 12 minutes
Version 2.3.35
Region Netherlands (nl)
Web Interface http://127.0.0.1:4040
Forwarding http://ca6d2c4cee3e.ngrok.io -> http://localhost:4000
Forwarding https://ca6d2c4cee3e.ngrok.io -> http://localhost:4000


Команда сгенерирует случайный динамический URL-адрес, по которому вы можете протестировать свой API и войти в систему со своими данными для входа, чтобы проверить, все ли работает.

После входа вы увидите:

GetMethod Called With Param: Id456

Всё работает!

Заключение


В этом небольшом руководстве показано, как создать базовый Go API с помощью Gin. Кроме того, мы узнали, как создать приложение для аутентификации и протестировать его с помощью ngrok.

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

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru