Никто не любит лишний раз вводить пароли. В мире веб-приложений протоколы для SSO (Single Sign-On) широко распространены и легко реализуемы благодаря встроенной в браузер возможности хранить cookie. Со стороны безопасности это не лучшее решение. Ряд популярных приложений, к примеру консольный клиент PostgreSQL (psql), предоставляют такую возможность для локальных подключений через сокеты UNIX. В этой статье мы рассмотрим, как это сделать с помощью опции SO_PEERCRED.

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

В этой статье речь идет о Linux, если не указано обратное.

 

Абстрактные сокеты Linux

Для взаимодействия с сервером мы будем использовать вариант UNIX domain sockets — abstract namespace sockets. В отличие от сетевых сокетов, в случае с локальными сокетами UNIX ядро знает, какой процесс подключается к сокету, и знает все о пользователе (создателе) процесса, что и позволяет переиспользовать системную аутентификацию.

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

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

Для решения этой проблемы в Linux существуют так называемые abstract namespace sockets. По своей сути они идентичны традиционным сокетам UNIX, но не являются файлами и автоматически исчезают с завершением процесса, который их создал. К ним также неприменимы обычные права доступа, и авторизация остается на совести приложения — но мы ведь к этому и стремимся.

Чтобы создать абстрактный сокет, нужно добавить в начало его «пути к файлу» нулевой байт. В остальном все так же, как с обычными.

 

Пишем сервер

Для начала мы напишем основу для сервера, пока без авторизации. Чтобы не писать разбор сообщений, мы сделаем всего две команды без аргументов: read (вернуть значение счетчика) и inc (увеличить счетчик на единицу).

Сокет мы назовем counter-server. Соответственно, путь его будет '\0counter-server'.

#!/usr/bin/env python3

import os
import socket

SOCK_FILE = '\0counter-server'

## Счетчик
counter = 0

## Создаем сокет
sock = socket.socket(family=socket.AF_UNIX, type=socket.SOCK_STREAM)
sock.bind(SOCK_FILE)
sock.listen()

while True:
    conn, _ = sock.accept()

    command = conn.recv(1024).decode().strip()

    if command == 'inc':
        print("Received an increment request")
        counter += 1
        response = "Success"
    elif command == 'read':
        print("Received a read request")
        response = "Counter value: {0}".format(counter)
    else:
    response = "Invalid command"

    conn.send(response.encode())
    conn.send(b'\n')
    conn.close()

Попробуем запустить его:

$ sudo ./counter-server.py 
Counter server started

Перейдем в другую консоль и попробуем подключиться с помощью socat. В случае с обычным stream-сокетом протокол был бы UNIX-CONNECT, но поскольку наш — «необычный», нужен ABSTRACT-CONNECT.

$ socat - ABSTRACT-CONNECT:counter-server 
inc
Success

$ socat - ABSTRACT-CONNECT:counter-server 
read
Counter value: 1

Продолжение доступно только участникам

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», увеличит личную накопительную скидку и позволит накапливать профессиональный рейтинг Xakep Score! Подробнее

Check Also

Разгоняем микроконтроллер. Как я выжал 620 МГц из совместимой с Arduino платы

Производительности всегда не хватает. Иногда проблему можно решить, просто обновившись до …

1 комментарий

  1. Аватар

    ch1s7ya

    02.08.2019 at 15:07

    «Со стороны безопасности это не лучшее решение», а какие варианты лучше?

Оставить мнение