Статьи

Phpseclib: Безопасное общение с удаленными серверами через PHP

PHP имеет библиотеку SSH2, которая обеспечивает доступ к ресурсам (оболочка, удаленное выполнение, туннелирование, передача файлов) на удаленной машине с использованием безопасного криптографического транспорта. Объективно, это трудоемкая и очень разочаровывающая задача для разработчика, чтобы реализовать ее из-за ее огромных возможностей конфигурации и сложного API с небольшим количеством документации.

Связь между клиентом и сервером

Пакет phpseclib ( PHP Scuure C ommunications Lib rary) имеет дружественный к разработчику API. Он использует некоторые необязательные расширения PHP, если они доступны, и в противном случае использует внутреннюю реализацию PHP. Чтобы использовать этот пакет, вам не нужны никакие не установленные по умолчанию расширения PHP.

Установка

composer require phpseclib/phpseclib

Это установит самую последнюю стабильную версию библиотеки через Composer .

Случаи использования

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

  1. Выполнение сценариев развертывания на удаленном сервере
  2. Загрузка и выгрузка файлов через SFTP
  3. Динамическая генерация ключей SSH в приложении
  4. Отображение вывода в реальном времени для удаленных команд, выполняемых на сервере
  5. Тестирование соединения SSH или SFTP

Подключение к удаленному серверу

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

  1. Ключ RSA
  2. Защищенный паролем ключ RSA
  3. Имя пользователя и пароль ( не рекомендуется )

Ключ RSA

Мы предполагаем, что у вас уже есть безопасный ключ RSA . Если вы не знакомы с созданием безопасной пары ключей RSA, вы можете прочитать эту статью . Для объяснения видео вы можете обратиться к разделу Создание и использование ключей SSH с серверов для хакеров.

Чтобы войти на удаленный сервер с использованием аутентификации по ключу RSA :

 namespace App;

use phpseclib\Crypt\RSA;
use phpseclib\Net\SSH2;

$key = new RSA();
$key->loadKey(file_get_contents('privatekey'));

//Remote server's ip address or hostname
$ssh = new SSH2('192.168.0.1');

if (!$ssh->login('username', $key)) {
    exit('Login Failed');
}

Защищенный паролем ключ RSA

Если ваши ключи RSA защищены паролем, не беспокойтесь. Phpseclib позаботится об этом конкретном случае использования:

 namespace App;

use phpseclib\Crypt\RSA;
use phpseclib\Net\SSH2;

$key = new RSA();
$key->setPassword('your-secure-password');
$key->loadKey(file_get_contents('privatekey'));

//Remote server's ip address or hostname
$ssh = new SSH2('192.168.0.1');

if (!$ssh->login('username', $key)) {
    exit('Login Failed');
}

Имя пользователя и пароль

Кроме того, чтобы войти на удаленный сервер, используя имя пользователя и пароль (мы не рекомендуем эту практику):

 namespace App;

use phpseclib\Net\SSH2;

//Remote server's ip address or hostname
$ssh = new SSH2('192.168.0.1');

if (!$ssh->login('username', 'password')) {
    exit('Login Failed');
}

Для других опций, таких как Без Аутентификации или Многофакторной аутентификации, пожалуйста, обратитесь к документации

Выполнение команд на удаленном сервере

Код для выполнения команд на удаленном сервере довольно прост. Вы вызываете метод $ssh->exec($cmd)

 namespace App;

use phpseclib\Crypt\RSA;
use phpseclib\Net\SSH2;

$key = new RSA();
$key->loadKey(file_get_contents('privatekey'));

//Remote server's ip address or hostname
$ssh = new SSH2('192.168.0.1');

if (!$ssh->login('username', $key)) {
    exit('Login Failed');
}

$ssh->exec('ls -la');

Выполнение нескольких команд на удаленном сервере

В реальных приложениях мы редко выполняем одну команду. Нам часто нужно обходить сервер с помощью cd Если вы попытаетесь выполнить несколько команд на удаленном сервере, как показано ниже, это не даст вам желаемого результата:

 $ssh->exec('pwd'); //outputs /home/username

$ssh->exec('cd mysite.com');

$ssh->exec('pwd'); //outputs /home/username

Причина вышеизложенного заключается в том, что вызов метода execexec Чтобы выполнить несколько команд без потери состояния:

 $ssh->exec('cd /home/username; ls -la'); //Lists all files at /home/username

Вы можете добавить столько команд, сколько пожелаете, с помощью точки с запятой или символа новой строки PHP_EOL

Например, если вы хотите запустить скрипт полного развертывания для Laravel:

 $ssh->exec(
      "git pull origin master" . PHP_EOL
        . "composer install --no-interaction --no-dev --prefer-dist" . PHP_EOL
        . "composer dump-autoload -o" . PHP_EOL
        . "php artisan optimize" . PHP_EOL
        . "php artisan migrate --force"
);

Выход при первой ошибке

В приведенном выше сценарии весь набор команд выполняется как один сценарий оболочки. Каждая команда будет выполнена, даже если некоторые из них потерпят неудачу, как в обычном сценарии оболочки. По умолчанию это нормально, но если нам нужно выйти при первой ошибке, мы должны изменить наш bash-скрипт. Это не что-то особенное для phpseclib , это связано со сценариями bash.

Если вы поместите опцию set -e

Например, измененная версия вышеуказанного сценария развертывания будет

 $ssh->exec(
    "set -e" . PHP_EOL
        . "git pull origin master" . PHP_EOL 
        . "composer install --no-interaction --no-dev --prefer-dist" . PHP_EOL
        . "composer dump-autoload -o" . PHP_EOL
        . "php artisan optimize" . PHP_EOL
        . "php artisan migrate --force"
);

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

Сбор выходных

Метод exec

 $output = $ssh->exec('ls -la');
echo $output;

Иногда, однако, он не возвращает весь вывод. Вы можете преодолеть это, передав закрытие как второй аргумент методу exec

 $ssh->exec(
    $deployment_script, function ($str) {
        $output .= $str;
});

echo $output;

Примечание. Вывод ошибки, если таковой имеется, также будет возвращен методом exec

Отображение живого выхода

Если вы хотите выполнить скрипт с помощью консольных команд и отобразить вывод в реальном времени, вы можете добиться этого, отображая вывод в базовом замыкании.

 $ssh->exec($deployment_script, function ($str) {
    echo $str;
});

Если вы хотите отобразить его в веб-браузере, вам нужно очистить (отправить) выходной буфер с помощью ob_flush()

 $ssh->exec(
    $deployment_script, function ($str) {
        echo $str;
        flush();
        ob_flush();
});

Другие параметры конфигурации

Также возможно установить много других доступных параметров конфигурации. Вы можете назвать их как $ssh->{option}

Например: $ssh->setTimeout(100)

Все варианты, которые мы еще не рассмотрели, представлены в таблице ниже:

вариант Случай использования
setTimeout($seconds) $ssh->exec('ping 127.0.0.1'); на хосте Linux никогда не вернется и будет работать бесконечно. setTimeout() Установка $timeout
write($cmd) Вводит команду в интерактивную оболочку.
read() Возвращает вывод интерактивной оболочки
isTimeout() Верните true, если результат последних $ssh->read()$ssh->exec() В противном случае он вернет false.
isConnected() Возвращает true, если соединение все еще активно
enableQuietMode() Подавляет stderr, поэтому ошибки не возвращаются
disableQuietMode() Включает в вывод stderr
isQuiteModeEnabled() Возвращает true, если тихий режим включен
enablePTY() Включить request-pty при использовании exec()
disablePty() Отключить request-pty при использовании exec()
isPTYEnabled() Возвращает true, если request-pty включен
getLog() Возвращает журнал пакетов, которые были отправлены и получены.
getServerPublicHostKey() Возвращает открытый ключ сервера. Возвращает false, если подпись сервера не подписана правильно с открытым ключом хоста.
getExitStatus() Возвращает состояние выхода команды SSH или false.
getLanguagesClient2Server() Возвращать список языков, которые поддерживает сервер, при получении материала от клиента.
getLanguagesServer2Client() Возвращать список языков, которые поддерживает сервер, при отправке материала клиенту.
getCompressionAlgorithmsServer2Client() Возвращает список алгоритмов сжатия, которые поддерживает сервер, при отправке содержимого клиенту.
getCompressionAlgorithmsClient2Server() Возвращает список алгоритмов сжатия, поддерживаемых сервером, при получении данных от клиента.
getMACAlgorithmsServer2Client() Возвращает список алгоритмов MAC, которые поддерживает сервер, при отправке материала клиенту.
getMACAlgorithmsClient2Server() Возвращает список алгоритмов MAC, поддерживаемых сервером, при получении данных от клиента.
getEncryptionAlgorithmsServer2Client() Возвращает список алгоритмов шифрования (симметричного ключа), которые поддерживает сервер, при отправке данных клиенту.
getEncryptionAlgorithmsClient2Server() Возвращает список алгоритмов шифрования (симметричного ключа), которые поддерживает сервер, при получении данных от клиента.
getServerHostKeyAlgorithms() Возвращает список алгоритмов хост-ключа (открытого ключа), поддерживаемых сервером.
getKexAlgorithms() Возвращает список алгоритмов обмена ключами, которые поддерживает сервер.

альтернативы

  1. LIBSSH2 — библиотека SSH — библиотека обеспечивает аналогичную функциональность, но ее использование немного менее интуитивно понятно , и для этого требуется, чтобы на сервере была установлена libssh2 , чего нет у большинства общих хостов.
  2. Компонент процессакомпонент Symfony для написания собственного скрипта для подключения и выполнения команд — как вы это делаете в обычном терминале. Это ограничивает нас в параметрах конфигурации, которые нам может потребоваться установить. Для достижения той же функциональности, что и описанные выше методы конфигурации, нам потребуется Process глубокое знание bash. Однако, если в вашем сценарии использования используется только локальный сценарий, это может оказаться полезным компонентом.

Резюме

В этой статье мы представили phpseclib , пакет, который предоставляет альтернативу для SSH2 . Мы рассмотрели параметры конфигурации, необходимые для начала работы, и приведенная выше таблица должна помочь вам заполнить пробелы и дать обзор других доступных параметров конфигурации.

Подробное описание взаимодействия на основе ключей см. В нашем предыдущем руководстве .

Как вы выполняете удаленные команды? Можете ли вы вспомнить какие-либо дополнительные варианты использования этой библиотеки? Кто они такие? Дайте нам знать об этом в комментариях!