[recovery mode] Symfony2 двухфакторная авторизация с помощью сертификата

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

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

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

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

Как работает аутентификация Symfony2 вообще?


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

Security состоит из четырех основных элементов: FirewallListeners, AuthenticationProviders, UserProviders и AuthenticationManager.

image

FirewallListeners внедряются классом Firewall. Они по цепочке обрабатывают запрос на этапе kernel.request. Основная их задача — создание неаутентифицированного токена, который будет аутентифицирован последующим AuthenticatedProvider'ом. Так же они отвечают за сериализацию и десериализацию токена в сесии (ContextListener), за редирект пользователя на https (ChannelListener), за ACL (AccessListener).

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

Посредством AuthenticationManager, листенеры взаимодействуют с AuthenticationProvider'ами. Основная задача провайдеров, посредством UserProvider загрузить пользователя и вернуть аутентифицированый токен — токен хотя бы с одной ролью.

AuthenticationManager реализует нестрогое соответствие между листенерами и провайдерами посредством supports() метода, что позволяет писать универсальные листенеры и провайдеры.

Все эти компоненты склеиваются воедино в SecurityExtension.

Как работает бандл?


Бандл добавляет еще один шаг аутентификации в виде генерации и скачивании сертификата пользователя.

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

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

После скачивания и установки сертификата в браузер, пользователь получает полный доступ. Бандл создает CertifiedUserToken, который наследуется от стандартного UserNamePasswordToken, а так же добавляет динамическую роль ROLE_CERT_AUTHENTICATED_FULLY, которая используется в вышеупомянутом AccessListener для проверки доступа.

Основная проверка клиентского сертификата ложится на backend сервер (nginx, apache), которые передают в symfony результат проверки и сам сертификат. Названия переменных настраиваются в конфиг. файле. Бандл лишь проверяет результат этой проверки. Проверка производится используя Symfony Expression Language и по-умолчанию имеет вид:

cert["subject"]["CN"] == token.getUserName() && request.server.get("CLIENT_CERT_OK") === "SUCCESS"

В контексте выражения: cert (массив в формате openssl_x509_parse), объект request и текущий token.

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

Система хранения (сервис zim_cert_auth.certificate_storage) использует три основных компонента: Formatter, Filters, Persister.
Formatter отвечает за преобразование x509 ресурса в формат хранения. На данный момент реализован только PKCS12 форматер.
Filter позволяет применить любые преобразования перед сохранением или извлечением.
Persister отвечает за физическое хранение сертификатов. На данный момент реализованы localfs и orm персистеры. Их предназначение понятно из названия. В планах добавить remotessh персистер который позволит хранить сертификаты на любом другом хосте используя scp.

Вы можете реализовать свои сервисы форматеров, персистеров, фильтров и определить их в config.yml

Управление сертификатами


Бандл добавляет несколько cli комманд для возвожности управления сертификатами. На данный момент существуют две команды:
zim:cert:dump и zim:cert:remove.

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

Всем спасибо.

© Habrahabr.ru