Никто не любит лишний раз вводить пароли. В мире веб-приложений протоколы для SSO (Single Sign-On) широко распространены и легко реализуемы благодаря встроенной в браузер возможности хранить cookie. Со стороны безопасности это не лучшее решение. Ряд популярных приложений, к примеру консольный клиент PostgreSQL (psql), предоставляют такую возможность для локальных подключений через сокеты UNIX. В этой статье мы рассмотрим, как это сделать с помощью опции SO_PEERCRED
.
В качестве примера мы напишем сервер, который просто хранит какое-то число, при этом пользователи из группы wheel
могут его изменять, а все остальные — только получать значение. Писать будем на Python, но все сказанное применимо к любому языку.
В этой статье речь идет о Linux, если не указано обратное.
Для взаимодействия с сервером мы будем использовать вариант UNIX domain sockets — abstract namespace sockets. В отличие от сетевых сокетов, в случае с локальными сокетами UNIX ядро знает, какой процесс подключается к сокету, и знает все о пользователе (создателе) процесса, что и позволяет переиспользовать системную аутентификацию.
В классической реализации сокеты UNIX представляют собой файлы. Это позволяет применить к ним права доступа и запретить пользователям или группам подключаться к ним, но более сложную модель привилегий на этом не построить.
Основной недостаток классической реализации — опция SO_REUSEADDR
для них не работает. Файл сокета должен быть создан процессом, который на нем слушает. Если процесс упал, а файл сокета остался, то новому процессу сначала нужно его удалить. Правильно написанный сервер должен использовать lock-файлы, чтобы предотвратить случайный запуск нескольких экземпляров процесса и обеспечить безопасное удаление старого файла.
Для решения этой проблемы в Linux существуют так называемые abstract namespace sockets. По своей сути они идентичны традиционным сокетам UNIX, но не являются файлами и автоматически исчезают с завершением процесса, который их создал. К ним также неприменимы обычные права доступа, и авторизация остается на совести приложения — но мы ведь к этому и стремимся.
Чтобы создать абстрактный сокет, нужно добавить в начало его «пути к файлу» нулевой байт. В остальном все так же, как с обычными.
Для начала мы напишем основу для сервера, пока без авторизации. Чтобы не писать разбор сообщений, мы сделаем всего две команды без аргументов: read
(вернуть значение счетчика) и inc
(увеличить счетчик на единицу).
Сокет мы назовем counter-server
. Соответственно, путь его будет '