[recovery mode] Symfony2 двухфакторная авторизация с помощью сертификата
Речь пойдет о Symfony2-CertAuthBundle — бандле для популярного фрейморка Symfony2, который позволяет легко внедрить двухфакторную аутентификацию на основе x509 сертификатов клиентов.
Иногда стандартной аутентификации в виде формы логина недостаточно чтобы надежно защитить проект.
Кто-то может подсмотреть, проснифить, любым другим способом выудить логин пароль, ну или просто взломать сайт и получить доступ ко всем учеткам.
Для тех, кто считает, что его проекту нужен более надежный метод защиты добро пожаловать под кат.
Установка подробно описана на гитхабе, ниже хочу рассказать о том как это работает и какие основные возможности бандла.
Как работает аутентификация Symfony2 вообще?
Компонент Security в симфони по-началу кажется очень сложным и запутаным. Но на самом деле, все очень просто и логично.
Security состоит из четырех основных элементов: FirewallListeners, AuthenticationProviders, UserProviders и AuthenticationManager.
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.
Так как бандл совсем молодой, в нем может не хватать функционала, который необходим в реальных проектах, поэтому любые пожелания по функционалу, общей работе бандла, пишите в коментариях или на гитхабе, будем реализовавывать все необходимые фичи.
Всем спасибо.