ssh2_connect
(PECL ssh2 >= 0.9.0)
ssh2_connect — SSH サーバーに接続する
説明
string
$host
,int
$port
= 22,array
$methods
= ?,array
$callbacks
= ?): resource|false
リモートの SSH サーバーとの接続を確立します。
一度接続すると、クライアントは ssh2_fingerprint() を使用してサーバーのホスト鍵を検証し、 パスワードもしくは公開鍵を使用して認証します。
パラメータ
host
-
port
-
methods
-
methods
は以下に示された4つのパラメータを持つ連想配列です。methods
は以下のパラメータのいくつかあるいは全てを含む連想配列インデックス 意味 サポートする値* kex 通知する鍵交換メソッドのリスト。優先する順にカンマ区切りにする。 diffie-hellman-group1-sha1
、diffie-hellman-group14-sha1
およびdiffie-hellman-group-exchange-sha1
hostkey 通知するホスト鍵メソッドのリスト。優先する順にカンマ区切りにする。 ssh-rsa
およびssh-dss
client_to_server クライアントからサーバーに送信されるメッセージのために優先する暗号化、 圧縮、メッセージ認証コード (MAC) メソッドを含む連想配列。 server_to_client サーバーからクライアントに送信されるメッセージのために優先する暗号化、 圧縮、メッセージ認証コード (MAC) メソッドを含む連想配列。 * - サポートする値は、 構成するライブラリがサポートしているメソッドに依存します。 追加情報については » libssh2 ドキュメントを参照ください。
client_to_server
とserver_to_client
は以下のパラメータのいくつかあるいは全てを含む連想配列インデックス 意味 サポートする値* crypt 通知する暗号化メソッドのリスト。 優先する順にカンマ区切りにする。 rijndael-cbc@lysator.liu.se
、aes256-cbc
、aes192-cbc
、aes128-cbc
、3des-cbc
、blowfish-cbc
、cast128-cbc
、arcfour
およびnone**
comp 通知する圧縮メソッドのリスト。 優先する順にカンマ区切りにする。 zlib
およびnone
mac 通知する MAC メソッドのリスト。 優先する順にカンマ区切りにする。 hmac-sha1
、hmac-sha1-96
、hmac-ripemd160
、hmac-ripemd160@openssh.com
およびnone**
注意: 暗号化、MAC メソッドの "
none
"
セキュリティ上の問題で、
none
は ビルド時に適切な ./configure オプションを使用して明示的に有効にしない限り、構成している » libssh2 によって無効にされます。 詳細は構成するライブラリのドキュメントを参照ください。 callbacks
-
callbacks
は以下のパラメータのいくつかあるいは全てを含む連想配列コールバックパラメータ インデックス 意味 プロトタイプ ignore SSH2_MSG_IGNORE
パケットを受信したときにコールする関数名void ignore_cb($message) debug SSH2_MSG_DEBUG
パケットを受信したときにコールする関数名void debug_cb($message, $language, $always_display) macerror パケットを受信したがメッセージ認証コードに失敗した場合にコールされる関数名。 もしコールバックが true
を返す場合、不整合は無視されます。 そうでない場合、接続は終了します。bool macerror_cb($packet) disconnect SSH2_MSG_DISCONNECT
パケットを受信したときにコールする関数名void disconnect_cb($reason, $message, $language)
戻り値
成功した場合にリソース、エラー時に false
を返します。
例
例1 ssh2_connect() の例
パケット送信時に 3des-cbc 、 パケット受信時に任意の強度の aes cipher、 両方向で無圧縮、 Group1 での鍵交換という設定で強制的に接続をオープンします。
<?php
/* もしサーバーが接続を終了した場合、ユーザーに通知する */
function my_ssh_disconnect($reason, $message, $language) {
printf("Server disconnected with reason code [%d] and message: %s\n",
$reason, $message);
}
$methods = array(
'kex' => 'diffie-hellman-group1-sha1',
'client_to_server' => array(
'crypt' => '3des-cbc',
'comp' => 'none'),
'server_to_client' => array(
'crypt' => 'aes256-cbc,aes192-cbc,aes128-cbc',
'comp' => 'none'));
$callbacks = array('disconnect' => 'my_ssh_disconnect');
$connection = ssh2_connect('shell.example.com', 22, $methods, $callbacks);
if (!$connection) die('Connection failed');
?>
参考
- ssh2_fingerprint() - リモートサーバーのフィンガープリントを処理する
- ssh2_auth_none() - "none" として認証する
- ssh2_auth_password() - SSH 上でプレーンなパスワードを使用した認証を行う
- ssh2_auth_pubkey_file() - 公開鍵を使用した認証を行う
- ssh2_disconnect() - Close a connection to a remote SSH server
User Contributed Notes 8 notes
Due to a lack of complete examples, here's a simple SSH2 class for connecting to a server, authenticating with public key authentication, verifying the server's fingerprint, issuing commands and reading their STDOUT and properly disconnecting. Note: You may need to make sure you commands produce output so the response can be pulled. Some people suggest that the command is not executed until you pull the response back.
<?php
class NiceSSH {
// SSH Host
private $ssh_host = 'myserver.example.com';
// SSH Port
private $ssh_port = 22;
// SSH Server Fingerprint
private $ssh_server_fp = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
// SSH Username
private $ssh_auth_user = 'username';
// SSH Public Key File
private $ssh_auth_pub = '/home/username/.ssh/id_rsa.pub';
// SSH Private Key File
private $ssh_auth_priv = '/home/username/.ssh/id_rsa';
// SSH Private Key Passphrase (null == no passphrase)
private $ssh_auth_pass;
// SSH Connection
private $connection;
public function connect() {
if (!($this->connection = ssh2_connect($this->ssh_host, $this->ssh_port))) {
throw new Exception('Cannot connect to server');
}
$fingerprint = ssh2_fingerprint($this->connection, SSH2_FINGERPRINT_MD5 | SSH2_FINGERPRINT_HEX);
if (strcmp($this->ssh_server_fp, $fingerprint) !== 0) {
throw new Exception('Unable to verify server identity!');
}
if (!ssh2_auth_pubkey_file($this->connection, $this->ssh_auth_user, $this->ssh_auth_pub, $this->ssh_auth_priv, $this->ssh_auth_pass)) {
throw new Exception('Autentication rejected by server');
}
}
public function exec($cmd) {
if (!($stream = ssh2_exec($this->connection, $cmd))) {
throw new Exception('SSH command failed');
}
stream_set_blocking($stream, true);
$data = "";
while ($buf = fread($stream, 4096)) {
$data .= $buf;
}
fclose($stream);
return $data;
}
public function disconnect() {
$this->exec('echo "EXITING" && exit;');
$this->connection = null;
}
public function __destruct() {
$this->disconnect();
}
}
?>
[EDIT BY danbrown AT php DOT net: Contains two bugfixes suggested by 'AlainC' in user note #109185 (removed) on 26-JUN-2012.]
Be careful when providing a specific hostkey order.
<?php
ssh2_connect('IP', 'port', array('hostkey'=>'ssh-rsa, ssh-dss'));
?>
Will only work when the public key of the server is RSA, and not DSA also as expected. This is caused by the empty space before the "ssh-dss".
So a similar code:
<?php
ssh2_connect('IP', 'port', array('hostkey'=>'ssh-rsa,ssh-dss'));
?>
Will work. The HOSTKEY method is overriden using exactly what you write, so no empty spaces are allowed.
This took me some time that you could save ;)
This page is out of date. Any of the SHA-1 in the Key Exchange Methods in the kex section should be discarded, due to Logjam (https://weakdh.org/logjam.html). If you continue to use them, connects will result in the following warning:
"Warning: ssh2_connect(): Error starting up SSH connection(-5): Unable to exchange encryption keys in ..."
The following is an example of what works. Also by removing the 'hex' section all together, results in libssl (https://libssh2.org/) falling back to discovering which is the strongest cipher to authenticate with.
<?php
if (!function_exists("ssh2_connect")) die("function ssh2_connect doesn't exist");
function ssh2_debug($message, $language, $always_display) {
printf("%s %s %s\n",$message,$language,$always_display);
}
/* Notify the user if the server terminates the connection */
function my_ssh_disconnect($reason, $message, $language) {
printf("Server disconnected with reason code [%d] and message: %s\n", $reason, $message);
}
$methods = array(
'hostkey'=>'ssh-rsa,ssh-dss',
// 'kex' => 'diffie-hellman-group-exchange-sha256',
'client_to_server' => array(
'crypt' => 'aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-cbc,blowfish-cbc',
'comp' => 'none'),
'server_to_client' => array(
'crypt' => 'aes256-ctr,aes192-ctr,aes128-ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-cbc,blowfish-cbc',
'comp' => 'none'));
$callbacks = array('disconnect' => 'my_ssh_disconnect');
foreach (array('192.168.1.1') as $host) {
$connection = ssh2_connect($host, 22, $methods, $callbacks);
if (!$connection) die("Connection failed:");
ssh2_auth_password($connection, 'user', 'my_password') or die("Unable to authenticate");
$stream = ssh2_exec($connection, 'free -m');
stream_set_blocking($stream, true);
$stream_out = ssh2_fetch_stream($stream, SSH2_STREAM_STDIO);
echo stream_get_contents($stream_out);
}
?>
Trying to include "aes256-cbc" in the encryption methods list caused an error. The documentation here may be out of date, and you might find a more accurate list of what values are acceptable by checking the libssh2 documentation at libssh2.org.
Hi,
If you are having problems with running a ssh2 session and it waits forever during the execution of stream_get_contents, it might be because the remote system has run the command and is now sitting at a # prompt waiting for the next command. I had this issue on a HP MSA box, here is the code to get around the issue.
Assuming you are connected with your authentication method and $ssh contains the handle.
<?php
$command = "check disk";
// Open a nice large window to stop wrapping
$stream = ssh2_shell ($ssh, 'xterm', null, 200, 200, SSH2_TERM_UNIT_CHARS);
// Hook into the error stream
$errorStream = ssh2_fetch_stream($stream, SSH2_STREAM_STDERR);
// Block the streams so we wait until they complete
stream_set_blocking ($stream, true);
stream_set_blocking($errorStream, true);
// Send the commands to the terminal
fwrite ($stream, $command . PHP_EOL );
// Wait give the terminal a chance to accept and start processing the command, this is a slow storage device after all
sleep(2);
// IMPORTANT BIT!! Send exit to the terminal to close the connection BEFORE WE WAIT FOR THE STREAM
fwrite ($stream, "exit" . PHP_EOL );
sleep (2);
// Print the output
echo stream_get_contents($stream);
$errortext=stream_get_contents($errorStream);
if (strlen($errortext) > 0) {
// Error Data
echo "Error Data: $errortext";
exit (1);
}
// All Good
exit (0);
?>
You can't use ssh2_exec with this method (well at lease I couldn't) because on executing the first command the stream gets blocked and then you can't run the exit command, whereas a terminal seems to use one session.
I hope this helps someone.
With Sara's help, I have the following SS2 class that is quite flexible. If anyone improves it, please feel free to let me know.
<?php
// ssh protocols
// note: once openShell method is used, cmdExec does not work
class ssh2 {
private $host = 'host';
private $user = 'user';
private $port = '22';
private $password = 'password';
private $con = null;
private $shell_type = 'xterm';
private $shell = null;
private $log = '';
function __construct($host='', $port='' ) {
if( $host!='' ) $this->host = $host;
if( $port!='' ) $this->port = $port;
$this->con = ssh2_connect($this->host, $this->port);
if( !$this->con ) {
$this->log .= "Connection failed !";
}
}
function authPassword( $user = '', $password = '' ) {
if( $user!='' ) $this->user = $user;
if( $password!='' ) $this->password = $password;
if( !ssh2_auth_password( $this->con, $this->user, $this->password ) ) {
$this->log .= "Authorization failed !";
}
}
function openShell( $shell_type = '' ) {
if ( $shell_type != '' ) $this->shell_type = $shell_type;
$this->shell = ssh2_shell( $this->con, $this->shell_type );
if( !$this->shell ) $this->log .= " Shell connection failed !";
}
function writeShell( $command = '' ) {
fwrite($this->shell, $command."\n");
}
function cmdExec( ) {
$argc = func_num_args();
$argv = func_get_args();
$cmd = '';
for( $i=0; $i<$argc ; $i++) {
if( $i != ($argc-1) ) {
$cmd .= $argv[$i]." && ";
}else{
$cmd .= $argv[$i];
}
}
echo $cmd;
$stream = ssh2_exec( $this->con, $cmd );
stream_set_blocking( $stream, true );
return fread( $stream, 4096 );
}
function getLog() {
return $this->log;
}
}
?>
Usage of 'hostkey' option makes sence when you need to check authenticity of the remote server, e.g. by means of ssh2_fingerprint function. For that purpose you specify a list of possible algorithms sorted by priority in descending order. Supported values also include 'ssh-ed25519', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384' and 'ecdsa-sha2-nistp521'.
For instance:
<?php
$ssh = ssh2_connect('192.168.3.1', 22, ['hostkey' => 'ssh-ed25519,ssh-rsa']);
$md5 = ssh2_fingerprint($ssh); // returns MD5 hash of ED25519 host key, or MD5 hash of RSA key if the key of previous type is absent
?>
Note, if the remote server does not have a key of appropriate type connection will fail:
<?php
$ssh = ssh2_connect('192.168.3.1', 22, ['hostkey' => 'ssh-dss']);
PHP Warning: ssh2_connect(): Error starting up SSH connection(-5): Unable to exchange encryption keys in php shell code on line 1
PHP Warning: ssh2_connect(): Unable to connect to 192.168.3.1 in php shell code on line 1
?>