Веб-приложения в защищённой среде
В последнее время в «Вопросах и ответах» часто спрашивают о различных нюансах работы Apache, WSGI и веб-приложений в Astra Linux Special Edition.
Работа веб-приложений в ОС СН Astra Linux Special Edition имеет ряд особенностей, обусловленных наличием мандатного разграничения доступом и режимов аутентификации пользователей.
Разработчик веб-приложения вправе самостоятельно решать вопросы идентификации и аутентификации пользователей его системы. Однако, при разработке подобных функций следует учесть возникающую необходимость сертификации разрабатываемых программных средств по требованиям отсутствия несанкционированного доступа (НСД) к данным.
Мы рекомендуем использовать встроенные механизмы защиты и идентификации пользователей с помощью защищённого веб-сервера Apache. Штатный веб-сервер Astra Linux Special Edition требует принудительной аутентификации во всех случаях взаимодействия и обеспечивает мандатное разграничение доступа.
Для разработчиков и администраторов предлагаются два механизма:
- PAM (использование базы локальных пользователей);
- ALD (использование базы доменных пользователей).
В основе PAM-аутентификации лежит метод простой аутентификации протокола HTTP (RFC 7617). Для использования в распределенных сетевых системах более подходящим является метод на базе протокола GSS-API (SPNEGO) с использованием механизма Kerberos.
Для того, чтобы настроить Apache на аутентификацию по Kerberos и использование мандатной защиты, необходимо:
- Создать принципала для сервиса:
ald-admin sgroup-svc-add HTTP/ --sgroup=mac
ald-client update-svc-keytab HTTP/ --ktfile=/etc/apache2/keytab
WSGI
После подключения пользователя Apache выполняет аутентификацию пользователя и определяет мандатные атрибуты подключения. После этого запрос обрабатывается процессом-обработчиком с UID аутентифицированного пользователя и соответствующими мандатными аттрибутами.
Модуль mod_wsgi для работы с приложениями WSGI присутствует в дистрибутиве ОС. Штатно поддерживается аутентификация и учитываются мандатные метки. Особенностью mod_wsgi в Astra Linux SE является возможность работы только в режиме embbeded. Т.о. при каждом запросе сервер в принудительном порядке создает процесс для запроса пользователя и происходит загрузка приложения. На данный процесс устанавливается мандатные атрибуты и UID подключенного пользователя.
Веб-сервер Apache из состава Astra Linux Special Edition запускает приложения WSGI для каждого пользовательского запроса. Такой подход обеспечивает необходимые условия для работы мандатной защиты данных. Следствием является увеличение потребления ресурсов и времени ответа на запросы.
Существует возможность использования запущенного WSGI-процесса для обработки последовательности запросов от пользователя в рамках постоянного HTTP-соединения. Веб-сервер не завершает запущенные обработчики WSGI в пределах параметра KeepAliveTimeout. Клиенты могут повторно использовать установленное соединение для ускорения обработки запросов.
Приложение Django
Настройка Django-приложения необходима для работы с переменной окружения REMOTE_USER, через которую Apache передает в веб-приложение идентификатор аутентифицированного пользователя.
Для этого необходимо в файле settings.py приложения указать следующие параметры:
MIDDLEWARE_CLASSES = ( '. ', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.RemoteUserMiddleware', '. ', ) AUTHENTICATION_BACKENDS = ( 'django.contrib.auth.backends.RemoteUserBackend', )
Аутентификация по Kerberos
Для правильной работы аутентификации по Kerberos необходимо:
Настройка сайта сводится к указанию типа аутентификации для обслуживаемого каталога:
AuthType Kerberos Krb5Keytab /etc/apache2/keytab KrbMethodNegotiate on KrbMethodK5Passwd off Require valid-user Order allow,deny Allow from all Require all granted
При использовании аутентификации по Kerberos (Astra Linux Directory) возникает необходимость получения билетов для подключения к внутренним модулям и сервисам, скрытым от пользователя. Для каждого подключения необходимо получить билет Kerberos на основе пользовательского запроса, что влечет за собой обращение к Kerberos KDC. Получается, что один пользовательский запрос приводит к необходимости нескольких запросов в Kerberos и, скорее всего, в LDAP.
Естественным способом повышения производительности служит использования функций кэширования, предоставляемых библиотекой Django. Поскольку речь идет о мандатной защите, могут использоваться следующие модули кэширования:
В обоих случаях необходимо настроить мандатные атрибуты на контейнер (БД и каталог соответственно).
При использовании для кэша PostgreSQL возможны две стратегии использования Kerberos (посредством GSS-API) при аутентификации в PostgreSQL:
- Использование данных аутентификации (билетов) пользователя.
- Делегирование полномочий веб-приложению.
Пример сайта для Apache
Listen *:8004WSGIScriptAlias / /usr/share/myapp/app.wsgi DocumentRoot /usr/share/myapp Options Includes FollowSymLinks MultiViews Order allow,deny Allow from all Require all granted KrbSaveCredentials on AuthType Kerberos KrbAuthRealms LAB50 Krb5Keytab /etc/apache2/keytab KrbMethodNegotiate on KrbMethodK5Passwd off require valid-user Alias /media /tmp Alias /static /usr/share/myapp/data/static LogLevel info ErrorLog /var/log/apache2/myapp.err CustomLog /var/log/apache2/myapp.log common
Авторизация пользователей в веб-приложении
При использовании ALD для аутентификации пользователей, авторизация в веб-приложении может быть выполнена стандартными функциями ППИ.
Получения идентификатора пользователя возможно двумя путями:
Самый простой способ авторизации — использование групп ALD. В этом случае возможно использовать стандартные функции: pwd.getpwnam, grp.getgrgid и др. Такой подход исключает необходимость непосредственного обращения в базу LDAP.
Получение метки текущего процесса
При создании сложных веб-приложений возникает задача получения мандатной метки пользователя. Получить мандатную метку в WSGI приложении можно используя библиотеку python-parsec.
import parsec mac = parsec.mac_get_pid(0) print "Мандатная метка данного процесса '<>'.".format(parsec.mac_to_text(mac))
Web-приложение на Python в Astra Linux с ALD авторизацией
Запустим в Astra Linux SE 1.5 написанное на Python (Django) web-приложение, возвращающее имя пользователя. Web-сервер — входящий в дистрибутив apache2 с модулем mod_python, авторизация через Astra Linux Directory. Проверим работу мандатного разграничения доступа.
Как настроить сервер — контроллер домена ALD и подключиться к нему клиентом в статье Настройка входа в систему с Astra Linux Directory.
Устанавливаем web-сервер (если еще не установлен), нужные нам модули apache и пакет с django
$ sudo apt-get install apache2 libapache2-mod-auth-kerb libapache2-mod-python python-django
Включаем модули apache, с которыми будем работать, отключаем лишний auth_pam, если ранее с ним работали, затем запускаем web-сервер
$ sudo a2dismod auth_pam $ sudo a2enmod python $ sudo a2enmod auth_kerb $ sudo service apache2 reload
Создаем принципала в ALD и добавляем его в группу mac
$ sudo ald-admin service-add HTTP/ald-server.example.ru $ sudo ald-admin sgroup-svc-add HTTP/ald-server.example.ru --sgroup=mac
Создаем файл ключа Kerberos и даем на него права пользователю www-data
$ KEYTAB="/etc/apache2/keytab" $ sudo ald-client update-svc-keytab HTTP/ald-server.example.ru --ktfile=$KEYTAB $ sudo chown www-data $KEYTAB $ sudo chmod 644 $KEYTAB
Блокируем дефолтный виртуальный сайт, конфигурация которого создается по-умолчанию и создаем в /etc/apache2/sites-available/ свой конфигурационный файл astra-django-project для виртуального хоста
$ sudo a2dissite default $ sudo vim /etc/apache2/sites-available/astra-django-project
ServerName ald-server.example.ru ServerAdmin useradmin@example.ru DocumentRoot /var/www/django_site AddDefaultCharset utf-8 Options -Indexes FollowSymLinks -MultiViews AllowOverride None AuthType Kerberos KrbAuthRealms EXAMPLE.RU KrbServiceName HTTP/ald-server.example.ru Krb5Keytab /etc/apache2/keytab KrbMethodNegotiate on KrbMethodK5Passwd off KrbSaveCredentials on require valid-user Order deny,allow Allow from all SetHandler python-program PythonHandler django.core.handlers.modpython SetEnv DJANGO_SETTINGS_MODULE django_site.settings PythonOption diango.root /var/www/django_site PythonPath "['/var/www/django_site/',] + sys.path" PythonAutoReload On SetHandler None SetHandler None SetHandler None ErrorLog /var/www/django_site/log/error.log LogLevel debug SetEnvIf Request_URI "\.jpg$|\.gif$|\.css$|\.js" is_static CustomLog /var/www/django_site/log/access.log combined env=!is_static
Добавляем созданную конфигурацию
$ sudo a2ensite astra-django-project
Но перезапускать apache еще рано, теперь надо создать наше django-приложение
$ cd /var/www/ $ sudo django-admin startproject django_site $ cd django_site $ sudo python manage.py startapp app
Создаем каталог для log-файлов, назначаем мандатные атрибуты каталогу с виртуальным сервером и перезапускаем web-сервер
$ cd django_site $ sudo pdpl-file 3:0:0xffffffffffffffff:ccnr /var/www/ $ sudo pdpl-file 3:0:0xffffffffffffffff:ccnr /var/www/django_site/ $ sudo service apache2 restart
На любом компьютере, который должен выступать в роли клиента, в firefox включаем negotiate авторизацию. Для чего открыть страницу about:config и добавить http:// в параметр network.negotiate-auth.trusted-uris .
Если все сделано правильно, то в браузере клиента, авторизованного через ald при обращении к http://ald-server.example.ru покажется стандартная начальная страница django.
Данные пользователя, в отличии от работы с PAM, передаются в зашифрованном виде, на сервере они расшифровываются и становятся доступны из стандартных http-заголовков. Напишем простое приложение, которое показываем имя пользователя, зашедшего на сервер.
В /var/www/django_site/django_site/settings.py добавляем наше приложение app
. INSTALLED_APPS = ( 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.messages', 'django.contrib.staticfiles', # Uncomment the next line to enable the admin: # 'django.contrib.admin', # Uncomment the next line to enable admin documentation: # 'django.contrib.admindocs', 'app', ) .
В /var/www/django_site/app/views.py создаем функцию, которое будет возвращать текущее время и авторизованного пользователя из request.META[‘REMOTE_USER’]
from django.http import HttpResponse import datetime def current_datetime(request): now = datetime.datetime.now() html = "It is now %s. User: %s " % (now, request.META['REMOTE_USER']) return HttpResponse(html)
В /var/www/django_site/django_site/urls.py создаем маршрут к нашему view
from django.conf.urls import patterns, url urlpatterns = patterns('', url(r'^$', 'app.views.current_datetime'), )
Для проверки работы мандатных ограничений можно провести эксперимент на конфигурации виртуального сервера default . Деактивируем виртуальный сервер с django, добавим проверочную конфигурацию и перезапустим web-сервер
$ sudo a2dissite astra-django-project $ sudo a2ensite default $ sudo service apache2 reload
На контроллере домена нужно создать доменного пользователя, и выставить ему ненулевой «максимальный уровень конфиденциальности» (например, 1). На компьютере — web-сервере в папке виртуального сервера например /var/www/ создать 2 файла и установить ненулевую мандатную метку на файл 1.html
echo "Hello world! 0" | sudo tee /var/www/0.html echo "Hello world! 1" | sudo tee /var/www/1.html sudo pdpl-file 1:0:0 /var/www/1.html
После чего зайти на клиентский компьютер под пользовательской доменной учетной записью с нулевым уровнем конфиденциальности и попытаться получить доступ к странице с ненулевым уровнем конфиденциальности http://ald-server.example.ru/1.html .
Результатом должен стать отказ в доступе. При этом в диагностическом сообщении об ошибке будет указано, что объект не найден ( ошибка 404 ), и не будет указана ошибка 403 (недостаточно прав). Такая диагностика исключает передачу информации о существовании объектов с высоким уровнем конфиденциальности, перекрывая возможный канал утечки информации.
Доступ к странице с нулевым уровнем конфиденциальности http://ald-server.example.ru/0.html должен предоставляться.
При входе на клиентский компьютер под пользовательской доменной учетной записью с ненулевым уровнем конфиденциальности должны быть доступны обе страницы.