18 января 2021

Clever Internet Suite. Аутентификация на SFTP-сервере с помощью SSH-ключа

    В статье "Передача файлов по SFTP" я подключался к SFTP-серверу используя парольную аутентификацию пользователя. Теперь давайте рассмотрим аутентификацию пользователя с помощью SSH-ключа. Для нее используется пара ключей: открытый (public, публичный) и закрытый (private, приватный). Публичный ключ хранится на сервере и представляет собой цифровой замок, который можно открыть только с помощью закрытого ключа. Считается, что аутентификация с помощью SSH-ключа обеспечивает более надежную проверку подлинности пользователя.
    Для начала сгенерируем пару ключей. Так как у меня уже установлен PuTTY (набор приложений с открытым исходным кодом для работы с сетевыми протоколами Telnet, SSH, SCP, SFTP), то я воспользуюсь для генерации ключей PuTTY Key Generator.
PuTTY Key Generator
Сохраним полученную пару ключей в файлы:
  1. Открытый ключ. Нажимаем кнопку "Save public key".
  2. Закрытый ключ без парольной фразы. Очищаем поля "Key passphrase" и "Confirm passphrase", и выбираем пункт меню "Conversions | Export OpenSSH key".
  3. Закрытый ключ с парольной фразой. Парольная фраза (пароль) будет использоваться для шифрования ключа на диске, поэтому без нее ключ использовать будет невозможно. Вводим парольную фразу и ее подтверждение в поля "Key passphrase" и "Confirm passphrase", и выбираем пункт меню "Conversions | Export OpenSSH key".
В качестве SFTP-сервера я использовал Bitvise SSH Server. Он тоже умеет генерировать пары ключей. Нажимаем "Manage host keys":
Bitvise SSH Server - Keypair management
генерируем новую пару ключей и экспортируем ее в формате OpenSSH аналогично PuTTYgen (один вариант "public key" и два варианта "keypair").
    Теперь пользователю SFTP-сервера разрешим аутентификацию с использованием открытого ключа и загрузим ему наш файл открытого ключа. У в Bitvise SSH Server это выглядит вот так.
Bitvise SSH Server - Edit virtual accaunt
    Можно приступать к программированию. Для работы с SFTP-сервером я снова воспользуюсь компонентой TclSFtp из библиотеки Clever Internet Suite. В ней за аутентификацию с использованием SSH-ключа отвечает свойство UserKey, которое имеет тип TclSshUserKey.
    Пример 1. Аутентификация пользователя с помощью закрытого ключа без парольной фразы:
procedure Test1;
var
  sftp: TclSFtp;
begin
  sftp := TclSFtp.Create(nil);
  try
    sftp.SshAgent := 'CIS clSFtp';
    sftp.Server   := 'localhost';
    sftp.Port     := 22;
    sftp.UserName := 'BlackCat';

    sftp.UserKey.PrivateKeyFile := 'bcPrivateKey.pem';

    try
      sftp.Open;
    except
      on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
    end;
  finally
    sftp.Free
  end;
end;
Судя по логу – аутентификация пользователя прошла успешно:
Bitvise SSH Server - Activity log
    Пример 2. Аутентификация пользователя с помощью закрытого ключа с парольной фразой. Если в первый пример в свойстве PrivateKeyFile мы укажем файл ключа с парольной фразой, то при попытке подключения мы получим ошибку:
EclCryptError: Встречено неверное значение тега ASN1
то есть, закрытый ключ расшифрован некорректно и программа не может прочитать его теги. Для корректной работы в свойстве UserKey.PassPhrase необходимо указать парольную фразу:
procedure Test2;
var
  sftp: TclSFtp;
begin
  sftp := TclSFtp.Create(nil);
  try
    sftp.SshAgent := 'CIS clSFtp';
    sftp.Server   := 'localhost';
    sftp.Port     := 22;
    sftp.UserName := 'BlackCat';

    sftp.UserKey.PrivateKeyFile := 'bcPrivateKeyPass.pem';
    sftp.UserKey.PassPhrase := '123';

    try
      sftp.Open;
    except
      on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
    end;
  finally
    sftp.Free
  end;
end;
    Пример 3. Предположим, что наш закрытый ключ хранится не в отдельном файле, а например, в базе данных. Для этого случая у класса TclSshUserKey есть метод Load, который позволяет загрузить ключ из массива байтов, потока и TStrings. Предположим, что наш закрытый ключ уже загружен в поток:
procedure Test3;
var
  sftp: TclSFtp;
  ms: TMemoryStream;
begin
  ms := TMemoryStream.Create;
  try
    ms.LoadFromFile('bcPrivateKeyPass.pem');

    sftp := TclSFtp.Create(nil);
    try
      sftp.SshAgent := 'CIS clSFtp';
      sftp.Server   := 'localhost';
      sftp.Port     := 22;
      sftp.UserName := 'BlackCat';

      sftp.UserKey.PassPhrase := '123';
      sftp.UserKey.Load(ms);

      try
        sftp.Open;
      except
        on E: Exception do
          Writeln(E.ClassName, ': ', E.Message);
      end;
    finally
      sftp.Free
    end;
  finally
    ms.Free;
  end;
end;
Обратите внимание, что парольная фраза должна быть обязательно присвоена свойству PassPhrase до вызова метода Load. Иначе ключ будет загружен не корректно и при подключении мы увидим ошибку:
EclSshError: Auth method is not supported

Комментариев нет:

Отправка комментария