LXF81:PHP
|
|
|
Содержание |
PHP Безопасная оболочка
Устали от людей, взламывающих ваш элитарный шифр rot26? Пол Хадсон научит вас защищаться.
Геродот однажды сказал: “Ни одно расширение не зови счастливым, пока не начал его использовать”. Ну хорошо, он сказал не совсем так, но в любом случае это справедливо: в составе PECL (PHP Extention Community Library) можно найти сотни странных, удивительных и великолепных расширений, ждущих когда же мы их попробуем, однако, пока вы не узнаете о существовании одного из них, пока не попробуете сами им воспользоваться – оно для вас все равно что не существует.
Эта статья посвящена изучению одной из скрытых драгоценностей PECL – расширению SSH2. Оно позволяет вам создавать безопасные зашифрованные каналы связи через Интернет, используя PHP, а затем использовать их для выполнения команд оболочки, переноса файлов и всего остального, что обычно делается при помощи SSH. Да, в работе через Web содержится определенный риск, но если вы а) поместили поле ввода пароля на странице и б) требуете указывать его для установки SSH-соединения, то вы находитесь в относительной безопасности. С другой стороны, если вы пишите скрипты, которые будете вызывать из локальной консоли, это расширение оказывается мощным средством для выполнения автоматических запросов к удаленным серверам вдали от назойливых взглядов хакеров.
Подключение
Я почти уверен, что расширение PHP SSH у вас не установлено, что не удивительно, поскольку оно не распространяется вместе с PHP, а библиотека от которой оно зависит (libssh2) очень редко включается в состав дистрибутивов. После того, как вы пройдете все этапы установки (они описаны во врезке справа), вам потребуется выполнить маленький тест, просто чтобы убедиться, что все в порядке. Попробуйте что-то вроде:
<?php $conn = ssh2_connect("192.168.133.98", 22); if (!$conn) die("Could not connect!"); echo ssh2_fingerprint($conn); ?>
Здесь вы видите две SSH-функции: ssh2_connect(), которая выполняет подключение к серверу (первый параметр) по указанному порту (второй параметр) и ssh2_fingerprint(), которая принимает подключение в качестве своего единственного параметра и выводит MD5-отпечаток сервера. Этот отпечаток никогда не меняется. В результате довольно легко опознать попытку атаки “man-in-the-middle” (при которой хакер пререхватывает ваше соединение вместо сервера, чтобы узнать пароль), поскольку полученное значение будет отличаться от ожидаемого.
Запустив этот сценарий, вы должны увидеть в качестве результата отпечаток для своего сервера. Он должен полностью совпадать с тем, который вы получаете, набрав ssh localhost на удаленной консоли за тем исключением, что при работе в командной строке SSH разделяет отпечаток на двухсимвольны блоки, отделенные двоеточиями.
Если вы подключаетесь, указав только IP-адрес (или доменное имя сервера) и порт, то библиотека SSH автоматически выберет устойчивое шифрование и устойчивый метод обмена ключами, но у вас есть возможность снизить планку, если клиент или сервер не понимают сильных алгоритмов. Чтобы изменить свойства подключения используется третий параметр функции ssh2_connect(). Он должен быть массивом, содержащим ключи “kex”, “client_to_server” и “server_to_client”. Значением первого ключа, “kex”, должен выступить алгоритм обмена ключами, который вы запрашиваете. Здесь можно указать diffie-hellman-group1-sha1, diffiehellman-group14-sha1 или diffie-hellman-group-exchange-sha1.
Параметры “client_to_server” и “server_to_client” сами являются массивами, определяющими объявленные алгоритм шифрования (“crypt”), метод сжатия (“comp”) и метод MAC (“mac”). Например, если вы хотите использовать довольно небезопасное SSH-соединение (это бывает возможно в доверенной сети, если для вас особенно важна скорость), то вы можете запросить шифрование по алгоритму 3DES вместо AES, используемого по умолчанию. Пример кода:
<?php $methods = array( "client_to_server" => array("crypt" => "3des-cbc"), "server_to_client" => array("crypt" => "3des-cbc") ); $conn = ssh2_connect("192.168.133.98", 22, $methods); if (!$conn) die("Could not connect!"); $methods_neg = ssh2_methods_negotiated($conn); echo "Keys negotiated with: {$methods_neg['kex']}\n"; echo "Client-to-server uses these methods:\n"; echo " Encryption: {$methods_neg["client_to_server"]["crypt"]}\n"; echo " Compression: {$methods_neg["client_to_server"]["comp"]}\n"; echo "Server-to-client uses these methods:\n"; echo " Encryption: {$methods_neg["server_to_client"]["crypt"]}\n"; echo " Compression: {$methods_neg["server_to_client"]["comp"]}\n"; ?>
Массив $methods содержит ключи “client_to_server” и “server_to_ client”, которые в свою очередь содержат массивы с ключом “crypt” и значением “3des-cbc”. CBC расшифровывается как Cipher Block Chaining (блочная передача зашифрованного текста), при его использовании передаваемые данные разбиваются на маленькие блоки и к каждому блоку перед шифрованием применяется операция XOR с предыдущим блоком, что приводит к тому что блоки, содержащие один и тот же зашифрованный текст оказываются совершенно непохожи друг на друга.
Если вы хотите попробовать настройку “comp”, укажите ее в массивах “client_to_server” и “server_to_client”. В качестве значения используйте “zlib”.
В нашем коде появляется новая функция, ssh2_methods_ negotiated(). Она возвращает массив, содержащий описание алгоритмов обмена ключами, сжатия и MAC (Message Authentication Code, код подтверждения подлинности сообщения), которые были в реальности использованы при этом подключении к удаленному серверу. Затем мы просто вывели на печать некоторые из полученных значений, но вы, возможно, захотите выполнить какие-то свои проверки этих значений, чтобы убедиться, что уровень безопасности вас устраивает.
Отправьте этот файл
Как любой другой пакет SSH, расширение SSH для PHP поддерживает SFTP и SCP, методы безопасной передачи файлов. Оба они используют одни и те же алгоритмы шифрования и поэтому одинаково безопасны, вся разница в том, хотите ли вы полноценное соединение напоминающее FTP, или же вам нужно только читать и записывать файлы в стиле cp.
Давайте сначала посмотрим на реализацию SCP, который был разработан чтобы осуществлять копирование файлов по принципу команды cp, но только через защищенное интернет-соединение. Рассмотрим две новых функции: ssh2_auth_password() выполняет аутентификацию нашего соединения, а ssh2_scp_send() копирует локальный файл на удаленный сервер. Для начала давайте создадим локальный файл, выполнив следующую команду:
echo "Hello, world" > hello.txt
А теперь передадим наше приветствие на сервер. Вам потребуется указать имя пользователя и пароль для подключения к серверу, для этого просто замените в следующем сценарии строки “username” и “password” на правильные значения.
<?php $conn = ssh2_connect("192.168.133.98", 22); if (!$conn) die("Could not connect!"); ssh2_auth_password($conn, "username", "password"); ssh2_scp_send($conn, "hello.txt", "/home/<имя удаленного пользователя>/hello.txt"); ?>
Обратите внимание, вам нужно указать будущее местоположение файла на удаленном сервере, в нашем случае это /home/<имя удаленного пользователя>/hello.txt. Получение файлов происходит так же просто, достаточно использовать функцию ssh2_scp_recv() и поменять местами второй и третий параметры.
ssh2_scp_recv($conn, "/home/yourremoteusername/hello.txt","hello.txt")
Второй способ передачи файлов – это использование SFTP, который позволяет выполнять FTP-подобные команды (например, mkdir, stat и так далее) по защищенному SSH-каналу. И, что более важно, SFTP в PHP реализован как оболочка для fopen, что значит вы можете использовать любые файловые функции PHP. Например:
<?php $conn = ssh2_connect("192.168.133.98", 22); if (!$conn) die("Could not connect!"); ssh2_auth_password($conn, "username", "password"); $sftp = ssh2_sftp($conn); $file = file_get_contents("ssh2.sftp://$sftp/home/paul/hello.txt"); echo $file; ?>
Итак, мы подключились к удаленному серверу и авторизовались на нем, указав имя пользователя и пароль. Затем мы вызвали функцию ssh2_sftp() для полученного соединения, которая выполнила SFTP- подключение и вернула его дескриптор. Именно этот номер потребуется для использования обычных файловых функций, так что мы присвоили его переменной $sftp. Теперь мы можем вызвать функцию file_get_ contents(), указав в ssh2.sftp:// в качестве протокола, и PHP прочитает содержимое файла через прозрачное SSH-подключение. Значение переменной $sftp нам потребовалось, чтобы указать, из какого потока выполнять чтение. И обратите внимание на то, что нам вновь пришлось полностью указать полный путь, поскольку по умолчанию поиск выполняется в корневом каталоге.
Я заказал безопасный канал
Нашим последним SSH-трюком будет получение полноценной SSH- оболочки, которую мы можем читать и писать так, будто это обычный терминал. PHP вновь интерпретирует ее как локальный файл, так что мы сможем использовать функции fread() and fgets() обычным образом. Требуется только придерживаться одного главного правила – нужно дать удаленному компьютеру время на то, чтобы выполнить нашу команду, иначе мы будем искать результат до того, как он будет готов. Итак, вот код:
<?php $conn = ssh2_connect("192.168.133.98", 22); if (!$conn) die("Could not connect!"); ssh2_auth_password($conn, "username", "password"); $stdio = ssh2_shell($conn); sleep(1); while($line = fgets($stdio)) echo $line; fwrite($stdio, "uname -a\n"); sleep(1); while($line = fgets($stdio)) echo $line; fclose($stdio); ?>
Все вплоть до вызова ssh2_shell() остается прежним. Новая для нас функция ssh2_shell() принимает SSH-соединение в качестве параметра и возвращает дескриптор, который указывает на стандартный поток ввода и стандартный поток вывода SSH-оболочки, на который программы выводят результаты своей работы. Именно сюда мы должны писать команды и отсюда же читать результаты.
Для начала выполним главное правило – нам придется использовать функцию sleep(), чтобы прервать выполнение на 1 секунду и дать серверу время очистить соединение и вывести шапку (строку приветствия удаленного пользователя). Затем мы используем цикл while, состоящий из одной строчки, чтобы прочитать и показать весь текст, переданный сервером (“Welcome to XYZServer!” и так далее). После того, как приглашение прочитано, мы пишем нашу команду “uname –a”. Она показывает системную информацию о компьютере, на котором запущена, такую как версия ядра, архитектура процессора и так далее.
После второго ожидания, пока эта команда отработает, мы делаем еще один однострочный цикл while и показываем полученные от сервера данные. В конце мы закрываем поток командой fclose(), чтобы прибраться за собой и на этом наш сценарий заканчивается. Красиво, правда?
Инструкции по установке SSH для PHP
- Установите OpenSSL и его библиотеку разработчика: libssl-dev или libssl-devel.
- Вытащите libssh2 из каталога Magazine/PHP вашего диска (ищите файл libssh2-0.13.tar.gz). Распакуйте его, выполните команду ./configure, а затем переключитесь на суперпользователя и запустите make all install.
- Возьмите расширение PHP SSH2 из каталога Magazine/PHP вашего диска (файл ssh2-0.10.tgz), распакуйте и запустите phpize, ./configure --with-ssh2, и, наконец, make. В результате вы получите файле ssh2.so в каталоге modules. Его нужно будет скопировать в ваш каталог расширений PHP.
- Выполните php –i | grep ini. Эта команда покажет вам местоположение файла php.ini, скорее всего, он находится в /etc/php.ini или /usr/local/lib/php.ini. Если у вас нет php.ini, то вам потребуется скопировать php.inirecommended из исходного дистрибутива PHP установленной у вас версии.
- Откройте файл php.ini и найдите в нем строчку ‘extension_dir’. Скорее всего, она будет показывать на примерно такой каталог: /usr/local/lib/php/extensions/.
- Поскольку вы все еще находитесь в php.ini, поищите в нем слово ‘dll’, и вы попадете в подраздел с описанием расширений. Вам нужно добавить туда вот такую строчку: extension=ssh2.so.
- Сохраните php.ini, а затем перенесите файл modules/ssh2.so, полученный на третьем шаге в каталог с расширениями PHP
- Запустите команду php –m. В полученном списке вы увидите ssh2.
Если нет, то, видимо, один из шагов вам не удался...