首页 > 解决方案 > PHP - 通过 socks5 代理从私钥连接到 sftp

问题描述

我正在尝试通过代理使用 rsa 私钥身份验证连接到 sftp。

use phpseclib\Net\SFTP;
use phpseclib\Crypt\RSA;

$proxyHost = 'proxy-host';
$proxyPort = 1080;
$fsock = fsockopen($proxyHost, $proxyPort);

$host = 'sftp.hostname.com';
$login = 'sftp_login';
$privatekey = file_get_contents('sftp_private.ppk');
$password = new RSA();
$password->loadKey($privatekey);
$request = "CONNECT $host:22 HTTP/1.0\r\nContent-Length: 0\r\n\r\n";

if(fputs($fsock, $request) != strlen($request)) {
  exit("premature termination");
}
while ($line = fgets($fsock, 1024)) {
    if ($line == "\r\n") {
      break;
    }
    //echo $line;
}
$sftp = new SFTP($fsock);
if (!$sftp->login($login, $password)) {
  exit('Login Failed');
}

我得到“登录失败”退出。

谢谢

标签: phpcurlproxyphpseclibfsockopen

解决方案


引用 https://github.com/phpseclib/phpseclib/issues/1460

端口 1080 通常用于 SOCKS5 代理,而不是 HTTP 代理。

假设您使用的是 SOCKS5 代理,那么这样的事情应该可以工作:

// SSH connection info
$port = 22;
$address = 'localhost';

// SOCKS5 connection info
$fsock = fsockopen('127.0.0.1', 1080, $errno, $errstr, 1);
if (!$fsock) {
    throw new \Exception($errstr);
}

$port = pack('n', $port);
$address = chr(strlen($address)) . $address;

$request = "\5\1\0";
if (fwrite($fsock, $request) != strlen($request)) {
    throw new \Exception('Premature termination');
}

$response = fread($fsock, 2);
if ($response != "\5\0") {
    throw new \Exception('Unsupported protocol or unsupported method');
}

$request = "\5\1\0\3$address$port";
if (fwrite($fsock, $request) != strlen($request)) {
    throw new \Exception('Premature termination');
}

$response = fread($fsock, strlen($address) + 6);
if (substr($response, 0, 2) != "\5\0") {
echo bin2hex($response) . "\n";
    throw new \Exception("Unsupported protocol or connection refused");
}

$ssh = new SSH2($fsock);
$ssh->login('username', 'password');
echo $ssh->exec('ls -latr');

也就是说,SOCKS5 有更多的花里胡哨,比这个示例代码当前容纳的要多。真的,最好是完整的 SOCKS5 课程。

希望它会帮助别人。


推荐阅读