Алгоритм установления соединения в протоколе SSH / Хабр

Небольшое введение в механизм engine openssl и подключение engine gost

Engine в openssl – это небольшая динамическая библиотека, которую openssl подгружает в runtime по требованию. Каждая такая библиотека, должна содержать в себе определенные символы (функции) для загрузки необходимых алгоритмов. В данной работе мы воспользуемся engine gost, который содержит в себе все необходимые отечественные криптографические алгоритмы.

Установка дичайше проста, например, и происходит следующим образом:

  1. Выкачиваете из репозитория реализацию данного энджина.

  2. собираете библиотеку с ним (mkdir build && cd build && cmake… && make):

    mkdir build
    cd build
    cmake ..
    make

  3. В директории bin (КОТОРАЯ ПОЯВИТСЯ В КОРНЕВОМ КАТАЛОГЕ ПРОЕКТА!!!) будет лежать динамическая библиотека gost.so – это и есть наш энджин. Его нужно будет перенести в директорию, где хранятся энджины openssl. Узнать месторасположение данной директории можно с помощью:

    openssl version -a | grep ENGINESDIR

  4. Дело за последним – нужно сказать openssl, где находится данный энджин и как он называется. Сделать можно это с помощью изменения файла конфигурации openssl.cnf. Месторасположение которого можно узнать с помощью:

    openssl version -a | grep OPENSSLDIR

    В конец данного файла нужно будет внести следующее содержимое:

    # в начало файла написать
    openssl_conf = openssl_def
    
    ...
    
    # в конец файла
    # OpenSSL default section
    [openssl_def]
    engines = engine_section
    
    # Engine section
    [engine_section]
    gost = gost_section
    
    # Engine gost section
    [gost_section]
    engine_id = gost
    dynamic_path = /path/to/engines/dir/with/gost.so
    default_algorithms = ALL
    init = 0

После этого данный энджин должен появится в openssl. Проверить его работоспособность можно заставив, например, сгенерировать приватный ключ в файле по ГОСТ Р 34.10-2022:

openssl genpkey -engine gost -algorithm gost2022_512 -pkeyopt paramset:A -out client_key.pem

Флаг -engine как раз говорит о том, какой engine нужно подгрузить перед началом работы для того, чтобы стал виден алгоритм генерации ключей для ГОСТ Р 34.10-2022.

Введение

Протокол Kerberos 5 сейчас активно используется для аутентификации. Особенностью данного протокола является то, что он осуществляет аутентификацию, базируясь на четырех китах:

  1. Симметричное шифрование;
  2. Хеширование;
  3. ЭЦП;
  4. Третья доверенная сторона.

Начиная с пятой версии появилась возможность использовать еще асимметричное шифрование (для электронной подписи). Более подробно на работе протокола Kerberos останавливаться не имеет смысла, ибо описание алгоритма можно посмотреть тут.

К сожалению, количество алгоритмов шифрования, хеширования и ЭЦП, которые использует данный протокол, не настолько велико, насколько хотелось бы, поэтому в данной статье я хочу показать, как добавить

легко и просто

собственные алгоритмы в

. Добавлять же мы будем наши отечественные алгоритмы: ГОСТ 28147-89 (aka Магма), ГОСТ Р 34.11-2022 (aka Стрибог) и ГОСТ Р 34.10-2022 (хотелось бы тоже иметь для него aka, но я не знаю:(). Готовое решение для данных алгоритмов можно его найти в

. На стороне клиента мы будем использовать аппаратные реализации алгоритмов ГОСТ в Рутокене ЭЦП 2.0 и их программные реализации в engine GOST для openssl. Но самый безопасный вариант хранения ключей – когда они генерируются непосредственно на Рутокене и никогда не покидают его память во время криптографических операций. Для такого варианта работы потребуется rtengine.

Перед тем, как приступить к внедрению алгоритмов, опишем основные места, где будут производится изменения. Внутри директории src/lib/crypto/ находятся реализации всех алгоритмов, отвечающих за симметричную криптографию и хеширование. В ней имеются 2 реализации этих криптографических алгоритмов: встроенная(builtin) и openssl.

Дабы сэкономить время и место, мы, естественно, будем добавлять реализации алгоритмов с помощью openssl, в котором они уже есть (ну или почти есть, но об этом чуть позже). Для добавления же асимметричных алгоритмов, нужно будет подправить плагин src/plugins/preauth/pkinit

Проверяем, что Рутокен ЭЦП 2.0 работает в системе

В терминале выполняем

$ pkcs11-tool --module /usr/lib/librtpkcs11ecp.so -T


Если увидите строку

Rutoken ECP <no label>

– значит всё хорошо.

Устанавливаем необходимые пакеты

sudo apt-get install libccid pcscd opensc

Если хотите добавить блокировку рабочего стола скринсейвером – дополнительно установите пакет

libpam-pkcs11

Установка TCP-соединения


Не буду подробно останавливаться на принципе работы стека TCP/IP, так как эта тема достаточно хорошо задокументирована в Рунете. При необходимости вы легко найдёте информацию.

На этом этапе происходит сетевое подключение клиента к серверу на TCP-порт, указанный в опции Port (по умолчанию: 22) в файле конфигурации сервера /etc/ssh/sshd_config.

Добавляем PAM-модуль с поддержкой ГОСТов

Загружаем библиотеку с

Открытие защищенного канала

2.1 Обмен идентификационными данными

После установки TCP-соединения, клиент и сервер (далее по тексту – стороны) обмениваются версиями SSH-протокола и другими вспомогательными данными, необходимыми для выяснения совместимости протоколов и для выбора алгоритмов работы.

2.2 Выбор алгоритмов: обмена ключами, шифрования, сжатия и т.п.

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

Список доступных алгоритмов обмена ключами на стороне клиента (используются для получения сессионного ключа) можно посмотреть командой:

ssh -Q kex

Список доступных в системе симметричных алгоритмов (используются для шифрования канала):

ssh -Q cipher

Список типов ключей для авторизации у клиента:

ssh -Q key-cert

Дополнено по замечанию onix74:

Все используемые в публикации команды актуальны для версии OpenSSH 7.6 из Ubuntu 18.04 LTS.

2.3 Получение сессионного ключа шифрования

Процесс получения сессионного ключа может отличаться в зависимости от версии алгоритма, но в общих чертах сводится к следующему:

Устанавливаем пакет с librtpkcs11ecp.so

Загружаем и устанавливаем DEB- или RPM-пакет по ссылке:

Аутентификация клиента

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

В общих чертах, аутентификация посредством ключей происходит следующим образом:

Уровень подключения

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

На этом уровне обеспечивается: мультиплицирование каналов (возможность работы множества каналов к одному серверу за счет объединения их в один канал), туннелирование и т.п.

Считываем сертификат

Проверяем, что на устройстве есть сертификат

$ pkcs11-tool --module /usr/lib/librtpkcs11ecp.so -O


Если после строчки:

Using slot 0 with a present token (0x0)

1) Создаём тестовый сертификат

Внимание! Описанные способы создания ключей и сертификатов подходят для тестирования и не предназначены для применения в боевом режиме. Для этого нужно использовать ключи и сертификаты, изданные доверенным центром сертификации вашей организации или аккредитованным удостоверяющим центром.
PAM-модуль создан защищать локальные компьютеры и подразумевает работу в небольших организациях. Поскольку пользователей немного, Администратор может сам следить за отзывом сертификатов и вручную блокировать учетные записи, как и за сроком действия сертификатов. PAM-модуль пока не умеет проверять сертификаты по CRL и строить цепочки доверия.

Регистрируем сертификат в системе

Убедитесь, что ваш сертификат выглядит как base64 файл:

Если ваш сертификат выглядит так:

то нужно сконвертировать сертификат из формата DER в PEM-формат(base64)

$ openssl x509 -in cert.crt -out cert.pem -inform DER -outform PEMСнова проверяем, что теперь все в порядке.

Добавляем сертификат в список доверенных сертификатов$ mkdir ~/.eid$ chmod 0755 ~/.eid$ cat cert.pem >> ~/.eid/authorized_certificates$ chmod 0644 ~/.eid/authorized_certificatesПоследняя строка защищает список доверенных сертификатов от случайного или намеренного изменения другими пользователями. Это исключает ситуацию, когда кто-то добавит сюда свой сертификат и сможет входить в систему от вашего имени.

Настраиваем аутентификацию


Настройка нашего модуля PAM совершенно стандартна и делается точно также, как и настройки других модулей. Создаём в файл

/usr/share/pam-configs/rutoken-gost-pam

содержащий полное имя модуля, включен ли он по умолчанию, приоритет модуля и параметры аутентификации.

В параметрах аутентификации есть требования к успешности операции:

Полное содержание файла

/usr/share/pam-configs/rutoken-gost-pamName: Rutoken PAM GOST
Default: yes
Priority: 800
Auth-Type: Primary
Auth: sufficient /usr/lib/librtpam.so.1.0.0 /usr/lib/librtpkcs11ecp.so

сохраняем файл, после этого выполняем$ sudo pam-auth-updateв появившемся окне ставим звёздочку около Rutoken PAM GOST и нажимаем OK

Проверяем настройку


Чтобы понять что всё настроено, но при этом не потерять возможность входа в систему введите команду

$ sudo login

Введите имя пользователя. Всё настроено правильно, если система потребует PIN-код устройства.

Настраиваем блокировку компьютера при извлечении токена

В состав пакета

libpam-pkcs11

входит утилита

pkcs11_eventmgr,

которая позволяет выполнять различные действия при возникновении событий PKCS#11.


Для настройки

pkcs11_eventmgr

служит файл конфигурации:

/etc/pam_pkcs11/pkcs11_eventmgr.confДля различных дистрибутивов Линукс, команда которая вызывает блокировку учетной записи при извлечении смарт-карт или токена будет отличаться. См. event card_remove.

Пример файла конфигурации представлен ниже:

pkcs11_eventmgr
{
    # Запуск в бэкграунде
    daemon = true;
     
    # Настройка сообщений отладки
    debug = false;
 
    # Время опроса в секундах
    polling_time = 1;
 
    # Установка тайм-аута на удаление карты
    # По-умолчанию 0
    expire_time = 0;
 
    # Выбор pkcs11 библиотеки для работы с Рутокен
    pkcs11_module = usr/lib/librtpkcs11ecp.so;
 
    # Действия с картой
    # Карта вставлена:
    event card_insert {
        # Оставляем значения по умолчанию (ничего не происходит)
        on_error = ignore ;
 
        action = "/bin/false";
    }
 
    # Карта извлечена
    event card_remove {
        on_error = ignore;
         
        # Вызываем функцию блокировки экрана
        
        # Для GNOME 
        action = "dbus-send --type=method_call --dest=org.gnome.ScreenSaver /org/gnome/ScreenSaver org.gnome.ScreenSaver.Lock";
        
        # Для XFCE
        # action = "xflock4";
        
        # Для Astra Linux (FLY)
        # action = "fly-wmfunc FLYWM_LOCK";
    }
 
    # Карта долгое время извлечена
    event expire_time {
        # Оставляем значения по умолчанию (ничего не происходит)
        on_error = ignore;
 
        action = "/bin/false";
    }
}

После этого добавьте приложение pkcs11_eventmgr в автозагрузку. Для этого отредактируйте файл .bash_profile:$ nano /home/<имя_пользователя>/.bash_profileДобавьте в конец файла строку pkcs11_eventmgr и перезагрузитесь.

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

Librtpam

Разработанный компанией «Актив» модуль добавляет двухфакторную аутентификацию пользователей по смарт-картам или USB-токенам с помощью асимметричных ключей по последним стандартам отечественной криптографии.

Рассмотрим принцип его работы:

Процесс аутентификации происходит следующим образом:

  1. На Рутокене выполняется поиск личного сертификата пользователя.
  2. Запрашивается PIN-код токена.
  3. Происходит подпись случайных данных на закрытом ключе непосредственно в чипе Рутокена.
  4. Полученная подпись проверяется с помощью открытого ключа из сертификата пользователя.
  5. Модуль возвращает вызвавшему приложению результат проверки подписи.

Можно аутентифицироваться по ключам ГОСТ Р 34.10-2022 (длины 256 или 512 бит) или устаревшему ГОСТ Р 34.10-2001.

За безопасность ключей можно не беспокоиться – они генерируются непосредственно в Рутокене и никогда не покидают его память во время криптографических операций.

Рутокен ЭЦП 2.0 сертифицирован ФСБ и ФСТЭК по НДВ 4, поэтому может применяться в информационных системах, обрабатывающих конфиденциальную информацию.

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

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

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

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

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

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

Авторизация и аутентификация

Процесс определения того, имеет или не имеет некоторый субъект доступ к некоторому объекту, называется авторизацией. Выше описана статическая схема авторизации в UNIX, основанная на постоянных правах доступа.

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

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

Право пользоваться входной телефонной линией может быть отнято у абонента при неуплате или перерасходе отведенного времени, для некоторых пользователей может быть ограничено время сеанса или право запускать определенные программы в определенное время (например, игры в рабочие часы), можно ограничить максимальный объем оперативной памяти и дискового пространства (а вот ограничение дискового пространства, кстати, вполне стандартный набор возможностей, use apropos quota ) и т. п.

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

Обычный сеанс работы пользователя начинается так: утилитаgetty, запущенная на какой-нибудь терминальной линии, обнаруживает активность на ней, выводит приглашение (обычно – пара строк, что-нибудь вроде Welcome to System такая-то / tty такой-то и _имя_компьютера login:) и вводит входное имя пользователя, после чего запускает программу login, которая выводит подсказку Password: и вводит пароль (он никак не отображается на экране, даже звездочками, иначе можно было бы его подглядеть или узнать его длину). Парольпрограммаlogin проверяет, и если он не подошел, выводит уже свое приглашение (обычно просто login:), вводит входное имя и пароль еще раз и снова проверяет.

Во многих версиях UNIX после нескольких ошибочных вводов пароля login начинает вставлять после очередного ввода временную задержку, которая с каждым разом увеличивается. Это делается для того, чтобы помешать злоумышленнику (или его каверзной программе) подобратьпароль, вводя прямо с терминала предполагаемые варианты.

При соединении по сети роль getty играет соответствующий сетевой сервис (например, демонsshd ); в зависимости от настроек он может самостоятельно проверять входное имя и пароль пользователя или вызывать для этого тот же самый login.

Убедившись, что пароль введен правильно, login запускает командный интерпретатор с установленными UID и GID, которые однозначно соответствуют входному имени.

Этот командный интерпретатор называется стартовым (login shell) и обладает некоторыми особыми свойствами, о них речь пойдет в лекции 11. Диалог с пользователем начинается именно со стартового shell, поэтому все команды, которые пользователь дает системе, будут так или иначе потомками этого командного интерпретатора – а значит, наследовать от него UID и GID.

Таким образом, права доступа любой программы (действительного субъекта), запущенной пользователем в этом сеансе работы, будут определяться правами номинального субъекта UID GID.

Аутентификация на сервере с использованием ключей ssh

Если вы успешно выполнили одну из вышеописанных процедур, вы сможете войти на удаленный хост без пароля учетной записи для удаленного хоста.

Базовый процесс выглядит аналогично:

Добавление алгоритма цифровой подписи

Ура! Мы приступаем к финальному разделу данной статьи и попробуем добавить собственный алгоритм электронной подписи. Не стоит пугаться, его добавить проще чем что-либо еще, так что давайте поскорее приступим… Хотя нет, подождите, для начала небольшая ремарка.

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

Ребята, не стоит вскрывать эту тему. Вы молодые, шутливые, вам все легко. Это не то. Это не Чикатило и даже не архивы спецслужб. Сюда лучше не лезть. Серьезно, любой из вас будет жалеть. Лучше закройте тему и забудьте, что тут писалось. Я вполне понимаю, что данным сообщением вызову дополнительный интерес, но хочу сразу предостеречь пытливых — стоп. Остальные просто не найдут.

Как-то так. Ну что же, если у вас хватило смелости приступить к этому, то давайте начнем. В данной статье я покажу вам два способа получения и хранения приватных ключей и сертификатов: в файловой системе и на токене. В сущности, для обоих применима Аксиома Эскобара, но для второго способа потребуется дополнительный энджин, так что если вы решитесь пойти путем шиноби, то милости просим в данный раздел, остальные могут его пропустить.

Добавление алгоритмов хеширования и симметричного шифрования

Как уже было ранее озвучено, мы не будем писать алгоритмы шифрования и хеширования с нуля, а воспользуемся готовой реализацией данных алгоритмов в openssl. Напрямую openssl не поддерживает в себе реализацию отечественных алгоритмов, но обладает мобильностью в данном вопросе и позволяет добавлять новые алгоритмы, используя механизм engine GOST для работы с ключами в файловой системе и, хранящие на токене — rtengine.

Добавление нового алгоритма цифровой подписи

Алгоритмы ЭЦП добавить куда проще чем те, что рассматривались ранее – придется заменить всего-то 2 файли! src/plugins/preauth/pkinit/pkcs11.h и src/plugins/preauth/pkinit/pkinit_crypto_openssl.c

Иерархия прав доступа

Выдача команды ls -l содержит, помимо прочего, информацию о правах доступа к файлу:

В приведенном примере файл/etc/anacrontab принадлежит пользователю root и группеadm, а файл/bin/sh – пользователю root и группеroot (совпадение имени пользователя и группы не случайно, но это все же разные ярлыки – UID и GID).

Как встроить открытый ключ при создании сервера

Если вы создаете новый сервер DigitalOcean, вы можете автоматически встроить открытый ключ SSH в учетную запись root нового сервера.

Внизу страницы создания дроплета есть опция для добавления ключей SSH на ваш сервер:

Если вы уже добавили файл открытого ключа в учетную запись DigitalOcean, вы сможете выбрать данную опцию (в примере выше указаны два существующих ключа: “Work key” и “Home key”). Чтобы встроить существующий ключ, нажмите на него, чтобы его выделить.

Если в вашу учетную запись еще не выгружен открытый ключ SSH, или если вы хотите добавить новый ключ, нажмите кнопку “ Add SSH Key”. При этом будет открыто диалоговое окно:

Вставьте содержимое открытого ключа SSH в поле “SSH Key content”. Если вы сгенерировали ключи, используя указанный выше метод, вы можете получить содержимое открытого ключа на локальном компьютере, введя следующую команду:

cat ~/.ssh/id_rsa.pub

Как скопировать открытый ключ на ваш сервер

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

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

Копирование открытого ключа вручную

Если у вас нет защищенного паролем доступа SSH к вашему серверу, вам нужно будет выполнить вышеуказанную процедуру вручную.

Содержимое файла id_rsa.pub нужно будет каким-то образом добавить в файл ~/.ssh/authorized_keys на удаленном компьютере.

Чтобы вывести содержимое ключа id_rsa.pub, введите на локальном компьютере следующую команду:

cat ~/.ssh/id_rsa.pub

Вы увидите содержимое ключа, которое может выглядеть примерно так:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCqql6MzstZYh1TmWWv11q5O3pISj2ZFl9HgH1JLknLLx44 tXfJ7mIrKNxOOwxIxvcBF8PXSYvobFYEZjGIVCEAjrUzLiIxbyCoxVyle7Q bqgZ8SeeM8wzytsY dVGcBxF6N4JS zVk5eMcV385gG3Y6ON3EG112n6d SMXY0OEBIcO6x PnUSGHrSgpBgX7Ks1r7xqFa7heJLLt2wWwkARptX7udSq05paBhcpB0pHtA1Rfz3K2B ZVIpSDfki9UVKzT8JUmwW6NNzSgxUfQHGwnW7kj4jp4AT0VZk3ADw497M2G/12N0PPB5CnhHf7ovgy6nL1ikrygTKRFmNZISvAcywB9GVqNAVE ZHDSCuURNsAInVzgYo9xgJDW8wUw2o8U77 xiFxgI5QSZX3Iq7YLMgeksaO4rBJEa54k8m5wEiEE1nUhLuJ0X/vh2xPff6SQ1BL/zkOhvJCACK6Vb15mDOeCSq54Cr7kvS46itMosi/uS66 PujOO xt/2FWYepz6ZlN70bRly57Q06J ZJoc9FfBCbCyYH7U/ASsmY095ywPsBo1XQ9PqhnN1/YOorJ068foQDNVpm146mUpILVxmq41Cj55YKHEazXGsdBIbXWhcrRf4G2fJLRcGUr9q8/lERo9oxRm5JFX6TCmj6kmiFqv Ow9gI0x8GvaQ== demo@test

Откройте удаленный хост, используя любой доступный метод. Например, если вы используете дроплет DigitalOcean Droplet как сервер, вы можете выполнить вход, используя веб-консоль на панели управления:

Когда вы получите доступ к учетной записи на удаленном сервере, вам нужно будет убедиться, что каталог ~/.ssh создан. При необходимости эта команда создаст каталог, а если каталог уже существует, команда ничего не сделает:

mkdir -p ~/.ssh

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

Копирование открытого ключа с использованием ssh-copy-id

Самый удобный способ скопировать открытый ключ на существующий сервер — использовать утилиту под названием ssh-copy-id. Поскольку этот метод очень простой, если он доступен, его рекомендуется использовать.

Инструмент ssh-copy-id входит в пакеты OpenSSH во многих дистрибутивах, так что, возможно, он уже установлен на вашей локальной системе. Чтобы этот метод сработал, вы должны уже настроить защищенный паролем доступ к серверу через SSH.

Для использования той утилиты вам нужно только указать удаленный хост, к которому вы хотите подключиться, и учетную запись пользователя, к которой у вас есть доступ через SSH с использованием пароля. Это учетная запись, куда будет скопирован ваш открытый ключ SSH.

Синтаксис выглядит следующим образом:

Копирование открытого ключа с помощью ssh

Если у вас нет ssh-copy-id, но вы активировали защищенный паролем доступ к учетной записи на вашем сервере через SSH, вы можете выгрузить ключи с помощью стандартного метода SSH.

Для выполнения этой задачи мы можем вывести содержимое нашего открытого ключа SSH на локальный компьютер и передать его через соединение SSH на удаленный сервер. С другой стороны, мы можем подтвердить существование каталога ~/.ssh в используемой нами учетной записи и вывести переданные данные в файл authorized_keys в этом каталоге.

Мы используем символ перенаправления >>, чтобы дополнять содержимое, а не заменять его. Это позволяет добавлять ключи без уничтожения ранее добавленных ключей.

Полная команда выглядит следующим образом:

Настройка openssl для работы с токенами (на примере рутокен)

Для работы с Рутокенами, аппаратно поддерживающими ГОСТ-криптографию, для openssl существует rtengine. Его установка достаточно проста и не сильно отличается от GOST, нужно только знать, что и где брать.

Недостатки субъект-субъектной модели unix. флаги и acl

За схемой прав доступа к файлам UNIX можно разглядеть механизм доменной ответственности, который тесно связан с О. Поскольку речь идет о правах, а не о сеансах доступа, мы имеем дело со статической моделью субъект-субъектных отношений со множественным субъектом. Множественный субъект в UNIX реализован не до конца.

Дело в том, что при трех различных способах доступа мы имеем возможность задать объекту только одну группу. Это означает, что средствами chmod/chownневозможно создать такое положение вещей, когда одна группа пользователей могла бы только читать из файла, другая – только запускать его, а всем остальным файл вообще не был бы доступен. Другое дело, что такое положение вещей встречается нечасто.

Несмотря на то что введение множественного субъекта в (идеальную) субъект-субъектную модель отношений позволяет решать любые вопросы предоставления доступа и отказа в нем, задачи, касающиеся изменения прав доступа некоторого субъекта к определенному объекту, остаются делом нелегким (см. лекцию 9).

Поэтому в разных версиях UNIX стали появляться расширения прав доступа, позволяющие устанавливать права на отдельные объекты системы. Поначалу это были так называемые флаги – дополнительные атрибуты файла, не позволяющие, например, переименовывать его или удалять из него информацию при записи (можно только дописывать). Флаги не устраняют главного недостатка, зато их легко организовать без изменения файловой системы: каждый флаг занимает ровно один бит (по принципу “есть – нет”) в линейке атрибутов, а любая файловая система имеет некоторый запас битов (стандартные атрибуты занимают только 12).

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

Многие файловые системы UNIX (XFS, SunUFS, FreeBSD-5 UFS и др.) поддерживают ACL (таблицы управления доступом) – неполные таблицы при объектах файловой системы, в которых указывается, каким образом для некоторых субъектов (пользователей или групп ) изменяются права доступа к этому объекту.

Стандартные команды работы с ACL – setfacl и getfacl – подробно описаны в руководстве, поэтому ограничимся лишь общими сведениями. В таблице используются те же ранги субъектов – “пользователь”, “группа” и “прочие”, что и в системе, при этом поля “пользователь” и “группа” могут указывать прямо на конкретный субъект или же косвенно – на “хозяина”, то есть на PID и GID файла.

Правило ACL имеет вид субъект: способ доступа; способы доступа используются тоже системные – r, w и x.

Все правила в ACL упорядочиваются по точности попадания в субъекта: сначала идут права вида “хозяин – пользователь”, потом – “именованный пользователь”, затем – “хозяин – группа”, следом – “именованная группа”, и на последнем месте – “остальные”.

На практике флаги или управление доступом использовать приходится нечасто. В большинстве случаев такая необходимость возникает в виде исключения – например, для временного поражения в правах или для временного предоставления доступа (легко сделать с помощью ACL ), а также при работе с очень важными файлами (например, в FreeBSD файл с ядром помечен как systemimmutable, т. е. неизменный; без выполнения команды chflags его нельзя ни переписать, ни сменить ему имя).

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

От теории к практике

Ну а теперь, думаю, у читателей назрел вполне закономерный вопрос: а зачем нужно знать все эти тонкости работы SSH-протокола, если для повседневной работы достаточно знаний команд создания ключей (ssh-keygen), открытия терминальной сессии (ssh), передачи файлов (scp)?

В качестве ответа, можно вспомнить тему о смене стандартного порта SSH на какой-то другой, которая постоянно становится причиной холивара на Хабре…

В собственной практике я не припомню ни одного смотрящего во внешнюю сеть сервера, который бы ежедневно не подвергался долбёжке на 22-й порт. В ситуации, если SSH у вас работает на стандартном порту (и ничем дополнительно не защищён), даже если аутентификация исключительно по ключам и никакие подборы паролей не пугают, то по причине постоянно валящихся запросов от недобросовестных клиентов сервер всё равно вынужден совершать массу бесполезной работы: устанавливать TCP-соединение, выбирать алгоритмы, генерировать сессионный ключ, отправлять запросы аутентификации, писать лог-файл.

В ситуации же, когда на 22-м порту ничего нет, или порт защищён с помощью iptables (либо надстройками над ним типа fail2ban), то злоумышленник будет дропнут ещё на этапе установки TCP-соединения.

Наиболее интересно описанное выглядит в виде таблицы*

КонфигурацияВероятность взломаПотери от флуда**
22 порт,
авторизация по паролю,
без защиты
высокаявысокие
22 порт,
авторизация по ключам,
без защиты
средняя***высокие
22 порт,
авторизация по ключам,
защита на основе ограничения неудачных попыток авторизации
низкаясредние****
Нестандартный порт,
авторизация по паролю,
без защиты
высокаянизкие
Нестандартный порт,
авторизация по ключам,
без защиты
средняя***низкие
Нестандартный порт,
авторизация по ключам,
защита на основе ограничения неудачных попыток авторизации
низкаянизкие

* — значения параметров (высокий, средний, низкий) носят относительный характер и служат только для сравнения показателей.

** — имеется ввиду расход ресурсов сервера (процессор, диск, сетевой канал и т.п.) на обработку лавины запросов, обычно идущих на 22-й порт.

*** — произвести взлом, если для авторизации используются RSA-ключи, очень сложно, однако неограниченное количество попыток авторизации делает это возможным.

**** — количество попыток авторизации ограничено, но серверу всё равно приходится обрабатывать их от большого количества злоумышленников.

Отключение аутентификации с помощью пароля на сервере

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

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

Когда вышеуказанные условия будут выполнены, войдите на удаленный сервер с помощью ключей SSH с учетной записью root или с учетной записью с привилегиями sudo. Откройте файл конфигурации демона SSH:

sudo nano /etc/ssh/sshd_config

Пишем сервер

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

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

#!/usr/bin/env python3

import os
import socket

SOCK_FILE = 'counter-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

Практическое использование

Подойдёт практически любой современный Линукс, для примера мы будем использовать xUbuntu 18.10.

Простой путь (через браузер)


Для получения тестового сертификата используйте

. Процесс займёт не более 5 минут.

Путь гика (через консоль и, возможно, компилятор)

Проверьте версию OpenSC $ opensc-tool --version

Если версия меньше чем 0.20, то обновитесь или соберите

из нашего GitHub-а (на момент выхода этой статьи релиз 0.20 ещё не выпущен) или из ветки master основного проекта OpenSC не позднее

Генерируем ключевую пару с параметрами:–key-type: GOSTR3410-2022-512:А (ГОСТ-2022 512 бит c парамсетом А), GOSTR3410-2022-256:A (ГОСТ-2022 256 бит с парамсетом A)

–id: идентификатор объекта (CKA_ID) в виде двузначных номеров символов в hex из таблицы ASCII. Используйте только ASCII-коды печатных символов, т.к. id нужно будет передать OpenSSL в виде строки. Например, ASCII-кодам “3132” соответствует строка «12». Для удобства, можно воспользоваться онлайн-сервисом конвертации строки в ASCII-коды.

$ ./pkcs11-tool –module /usr/lib/librtpkcs11ecp.so –keypairgen –key-type GOSTR3410-2022-512:A -l –id 3132

Далее будем создавать сертификат. Ниже будет описано два пути: первый через УЦ (мы будем использовать тестовые УЦ), второй – самоподписанный. Для этого сначала надо установить и настроить OpenSSL версии 1.1 или новее для работы с Рутокен через специальный модуль rtengine используя руководство Установка и настройка OpenSSL.Например: для ‘–id 3132’ в OpenSSL надо указывать “pkcs11:id=12”.

Можно воспользоваться услугами тестового УЦ, коих много, например, вот, вот и вот, для этого создадим запрос на сертификат

Другой вариант – можно поддаться лени и создать самоподписанный$ openssl req -utf8 -new -keyform engine -key “pkcs11:id=12” -engine rtengine -out req.csr

Загружаем сертификат на устройство$ openssl req -utf8 -x509 -keyform engine -key “pkcs11:id=12” -engine rtengine -out cert.cer

Разделяемые каталоги

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

Значит, улучив момент, можно этот файлподменить: процесс файл закрыл, потом открыл, да уже другой. Что делать? На такой случай придуман еще один атрибут: так называемый t-бит:

Несмотря на то что ls ставит tвместо x, t-бит – еще один, десятый (формально – девятый, так как биты принято нумеровать с нуля) бит атрибутов каталога; в восьмеричной записи права на /tmp выглядели бы как 1777.

В свое время t-бит придумали для исполняемых файлов. Процесс, запущенный из файла с этим атрибутом, нельзя было выгружать из памяти в область подкачки (swap), отсюда и его официальное название: бит навязчивости (stickybit).

Годы идут, политика распределения оперативной памяти меняется, и это свойство t-бита давно не используется (в некоторых системах нынче выгружаются даже ненужные страницы памяти ядра). Навязчивость каталогу ни к чему, поэтому для каталога t-бит имеет другой смысл: пользователь, которому разрешена запись в каталог, имеющий атрибутt, может изменять только названия собственных файлов (проверяется совпадение UID).

Реализация алгоритма хеширования

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

Реализация алгоритма шифрования

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

Создание ключей ssh

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

Для этого мы можем использовать специальную утилиту ssh-keygen, которая входит в стандартный набор инструментов OpenSSH. По умолчанию она создает пару 2048-битных ключей RSA, что подходит для большинства сценариев использования.

Сгенерируйте на локальном компьютере пару ключей SSH, введя следующую команду:

ssh-keygen

Создание приватного ключа и сертификата для принципала, kdc и уц

За основу данной инструкции была взята инструкция по настройке kerberos. Я лишь адаптировал ее для работы с русскими алгоритмами, так что частично заглядывайте туда.

Суперпользователь. подмена идентификатора

Пользователь root (он же “суперпользователь” ) имеет нулевые UID и GID и играет роль доверенного субъекта UNIX. Это значит, что он не подчиняется законам, которые управляют правами доступа, и может по своему усмотрению эти права изменять.

Большинство настроек системы доступны для записи только суперпользователю (даже если файл имеет права доступа 0444, root все равно может в него писать).

Вообще, root – страшный человек! Он может удалить все ваши файлы, хотите вы того или нет. Он может отредактировать /etc/passwd и вообще может все. Как правило, парольroot знает толькосистемный администратор.

В полном согласии с О, он отвечает за все, что творится в системе, – раз уж он все это в состоянии изменить. Именно суперпользователю принадлежит файл/etc/group, который определяет, в какие еще группы, помимо отмеченных в /etc/passwd, входят пользователи системы.

Именно с нулевыми идентификаторами пользователя и группы запускается login: это позволяет ему в дальнейшем “становиться любым пользователем”, меняя собственные UID и GID.

Многие другие системные действия тоже требуют прав root, но по здравом рассуждении могут быть доверены обычному (не супер) пользователю. Например, управлять очередью отсылаемых электронных писем и передавать эти письма по назначению может процесс, не обладающий правами root, однако ему нужен полный доступ к очереди писем.

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

Поле SHELL у псевдопользователя часто равно /sbin/nologin (программа выдает This account is currently not available и немедленно завершается), а поле HOME – /nonexistent (каталог, которого в системе нет).

Пользователь может сам поменять себе пароль (а иногда SHELL и GECOS) с помощью команды passwd. Это простое и довольно обыденное действие, с учетом всего сказанного выше, невозможно. В самом деле: процесс, запущенный пользователем, будет иметь его UID, а файл passwd принадлежит root, и только процессам с нулевым UID доступен для записи.

Для этого в файловой системе предусмотрено еще два атрибута – setuid и setgid. При запуске файла, имеющего атрибутsetuid, система создает процесс, UID которого равен UIDэтого файла, а не UID процесса-родителя.

Такова программаpasswd: запустив ее, пользователь получает праваroot, но его действия ограничены возможностями этой программы.

Как видно, ls отображает setuid как s на месте пользовательского x-бита (x-бит никуда не делся, просто без него setuid все равно не имеет смысла).

Сходным образом работает и setgid, наследуя GID процесса от выполняемого файла. Подмена GID нужна в тех случаях, когда необходимо и открыть доступ к файлу, и сохранить реальный идентификатор пользователя – например, для записи рекордов в игре rogue.

Кстати, бессмысленно ставить setuid или setgidсценариям, поскольку процесс запустится из файла, содержащего интерпретатор, а файл со сценарием будет всего лишь параметром командной строки.

Подмена идентификатора, особенно на суперпользовательский (т. н. setuidroot), – дело весьма деликатное. Что если программаpasswd имеет какие-нибудь еще способности, кроме как изменять /etc/passwd строго в соответствии с документацией?

Имея дело со свободно распространяемыми системами, мы всегда можем заглянуть в исходные тексты этой программы и убедиться, что авторы не имели в виду ничего предосудительного. Но вдруг у них случайно так вышло, что при определенных условиях passwd может запустить из текущего каталога программу с именем hack’em’all?

Тогда все действия этой программы будут выполняться от имени root (наследованиеUID!) – действия, предусмотренные не системой, а каким-то бесправным пользователем, которому всего только и разрешено было что менять себе пароль.

Даже если passwd (или другую утилиту, занимающуюся аутентификацией ) нельзя спровоцировать ничего сделать сверх предписанного, она по крайней мере должна прочитать файл с ключами от всех паролей ( shadow или master.passwd ).

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

Во избежание этой – гипотетической – опасности, системы, в которых применяется схема Trusted ComputingBase (например, ALT Linux), для каждого пользователя держат отдельныйфайл/etc/tcb/имя_пользователя/shadow.

Стоит отметить, что строгая реализация правил простой модели безопасности (NoRU/NoWD – секретность или NoWU/NoRD – надежность) средствами UNIX невозможна. И дело даже не в наличии доверенного субъекта – root, а в том, что правила вида “No что-нибудь Down” противоречат О.

Учетные записи

Все данные о пользователях UNIX хранит в файле /etc/passwd в текстовом виде. Каждому пользователю соответствует одна строка, поля которой разделяются двоеточиями:

или, пользуясь собственной терминологией UNIX,

Полное имя пользователя сокращено до GECOS оттого, что в незапамятные времена кто-то из разработчиков UNIX использовал сервер печати под управлением GeneralElectricComprehensive Operating System.

В единственном поле, содержимое которого не используется UNIX, пришлось хранить пароль для передачи документов на печать. Информация в /etc/passwd – несекретная, этот файл доступен для чтения любому пользователю.

Возникает вопрос: а где хранится системныйпароль пользователя? Ответ: нигде. UNIX не хранит пароли ни открытым текстом, ни в зашифрованном виде. Вместо пароля хранится ключ (hash) – последовательность символов, получаемая из пароля невосстановимым шифрованием.

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

Вычислить пароль, имея один только ключ, нельзя; все, что остается предполагаемому злоумышленнику, – это попытаться его подобрать (придумывать варианты пароля и сравнивать ключи ).

По-хорошему, именно ключ никому, кроме самой системы, знать и не надо. К тому же, если располагать некоторыми знаниями о структуре пароля (день рождения, содержимое GECOS, имя любимой кошки и т. п.), подобрать его может быть очень просто.

Можно воспользоваться весьма мощным компьютером (например, вычислительным кластером) и попросту подобрать этот пароль “в лоб”. Чтобы исключить принципиальную возможность подбора, в современных версиях FreeBSD и Linux ключ из файла /etc/passwd удалили в файл, недоступный для чтения никому, кроме пользователя root.

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

Похожее:  Двухфакторная Авторизация на Linux сервере / Хабр

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *