PHP-phpseclib:如何通过带基础认证的Socks5代理连接SSH主机
带用户名密码认证的Socks5代理连接SSH实现
原示例仅支持无认证的Socks5代理,要实现带用户名密码基础认证的Socks5代理连接SSH,需要修改握手流程,加入认证步骤,完整代码如下:
$proxyHost = '127.0.0.1'; $proxyPort = 1080; $proxyUser = '你的代理用户名'; $proxyPass = '你的代理密码'; $sshHost = '目标SSH主机'; $sshPort = 22; $sshUser = 'SSH用户名'; $sshPass = 'SSH密码'; // 连接Socks5代理 $fsock = fsockopen($proxyHost, $proxyPort, $errno, $errstr, 10); if (!$fsock) { throw new \Exception("代理连接失败: $errstr"); } // 第一步:Socks5握手,告知支持用户名密码认证(方法码2) $authMethods = "\x05\x01\x02"; // 版本5,1种方法,方法2(用户名密码认证) if (fwrite($fsock, $authMethods) != strlen($authMethods)) { throw new \Exception('代理握手请求发送失败'); } // 读取代理返回的认证方法 $methodResponse = fread($fsock, 2); if ($methodResponse != "\x05\x02") { throw new \Exception('代理不支持用户名密码认证,返回方法: ' . bin2hex($methodResponse)); } // 第二步:发送用户名密码认证请求 $authReq = "\x01" . chr(strlen($proxyUser)) . $proxyUser . chr(strlen($proxyPass)) . $proxyPass; if (fwrite($fsock, $authReq) != strlen($authReq)) { throw new \Exception('认证请求发送失败'); } // 读取认证结果 $authResult = fread($fsock, 2); if ($authResult != "\x01\x00") { throw new \Exception('代理认证失败,返回码: ' . bin2hex($authResult)); } // 第三步:请求建立到SSH主机的连接 $sshPortPacked = pack('n', $sshPort); $sshHostLen = chr(strlen($sshHost)); $connectReq = "\x05\x01\x00\x03" . $sshHostLen . $sshHost . $sshPortPacked; if (fwrite($fsock, $connectReq) != strlen($connectReq)) { throw new \Exception('连接SSH请求发送失败'); } // 读取连接响应 $responseLen = strlen($sshHost) + 6; $connectResponse = fread($fsock, $responseLen); if (substr($connectResponse, 0, 2) != "\x05\x00") { throw new \Exception('代理连接SSH失败,响应: ' . bin2hex($connectResponse)); } // 连接SSH $ssh = new SSH2($fsock); if (!$ssh->login($sshUser, $sshPass)) { throw new \Exception('SSH登录失败'); } // 执行命令 echo $ssh->exec('ls -latr'); fclose($fsock);
关键修改说明:
- 握手阶段:将原请求的无认证方法,改为指定支持用户名密码认证(方法码
0x02),确保代理返回该认证方法后才继续流程 - 认证阶段:新增用户名密码认证请求,格式遵循Socks5协议规范:版本
0x01+ 用户名长度 + 用户名 + 密码长度 + 密码 - 结果校验:分别校验代理返回的认证结果和SSH连接结果,确保每一步都成功后再进行SSH登录
内容的提问来源于stack exchange,提问作者Grzegorz Porada
相关产品推荐
相关产品推荐

