PHPSeclib Public 本地主机上的密钥验证成功;部署时失败

PHPSeclib Public Key Authentication Successful on Localhost; Failing when deployed

我创建了一个脚本,它使用 phpseclib 扩展连接到服务器,使用 public 密钥自动(如您所见 here),通过使用生成密钥对ssh-keygen.

我现在面临的是,当我 运行 来自本地主机的 php 脚本时,连接工作得很好,但是当我 运行 来自服务器的脚本时,我总是尝试登录失败,并报告以下错误:

SSH_MSG_USERAUTH_FAILURE

(我在尝试 $sftp->login() 后使用 $sftp->getLastError() 时得到的结果)。

知道为什么会这样吗?????

更新

认为可能是file_get_contents()的一些错误,所以我检查了一下,确实是key的值。我也直接将私钥粘贴到PublicKeyLoader::load()函数中,同样的错误发生了,所以不是这个原因。

我认为发生问题的主要日志事件是,运行使用完全相同的脚本尝试与目标服务器建立连接时:

来自本地主机(工作):

NET_SSH2_MSG_SERVICE_REQUEST;
NET_SSH2_MSG_SERVICE_ACCEPT;
NET_SSH2_MSG_USERAUTH_REQUEST (ssh-connection none); 
NET_SSH2_MSG_USERAUTH_FAILURE; 
NET_SSH2_MSG_USERAUTH_REQUEST(ssh-connection publickey); 
NET_SSH2_MSG_USERAUTH_PK_OK;

来自服务器(不工作):

NET_SSH2_MSG_SERVICE_REQUEST;
NET_SSH2_MSG_SERVICE_ACCEPT;
NET_SSH2_MSG_USERAUTH_REQUEST (ssh-connection none); 
NET_SSH2_MSG_USERAUTH_FAILURE;
NET_SSH2_MSG_USERAUTH_REQUEST (ssh-connection publickey); 
NET_SSH2_MSG_USERAUTH_FAILURE;

我生成了三个密钥对,运行 本地主机和服务器-客户端测试,我总是得到上面显示的结果。当我回显出来时,我肯定得到了密钥,不用担心它不是加密的 OpenSSH 私钥,这不是原因(phpseclib 不支持),然后在本地主机上也会失败(我测试过)。

所以看起来它在服务器上的 public 密钥身份验证步骤中失败了,尽管我使用的是完全相同的脚本,尽管我在回显检索到的时得到了完全正确的密钥键出,也在服务器端。

然后我检查了如果我更改密钥的单个字符会发生什么;如果重现上面显示的 SSH - 日志,但没有。如果我这样做,脚本会在记录任何内容之前中断,抛出 phpseclib3\Exception\NoKeyLoadedException: Unable to read key 异常。

由此我得出结论,唯一的问题可能是密钥在发送到服务器之前以某种错误的方式编码,并且服务器因此而误解了密钥。

考虑到这一点,我发现 phpseclib 根据 this 需要 paragonie 包,并且 paragoniephpseclibs 依赖项之一做一些 base64 - 编码。因此,我认为可能是由于某种原因,用于发送密钥的编码没有正确完成,然后去检查 phpseclib 扩展是如何安装在服务器上的(由服务器管理员完成,而不是由我)。

原来它是一个 plesk 服务器,根据 this,它要求您以一种不寻常的方式上传新的作曲家包,即通过 composer.json 文件。我只通过命令提示符、SSH 直接在服务器上安装了 composer 包,或者安装到本地环境 + 部署在服务器上。这两个都不起作用,上面的说明也不起作用。

然后我检查了 composer.json 文件,发现它的内容是:

{ 
  "name": "packagex/packagex", 
  "type": "plugin", 
  "description": "secret_description", 
  "keywords": ["secret_keyword"], 
  "homepage": "secret_url", 
  "license": "secret_license", 
  "authors": [ { "name": "secret_name", "email": "secret_mail" } ],
  "require": 
    {
      "php": ">=5.3", 
      "phpseclib/phpseclib": "^3.0"
    }
}

该文件已经包含一个扩展名,我们不能修改它,但我们需要添加 phpseclib。为此,行 "phpseclib/phpseclib": "^3.0" 只是添加到 JSON 的 require 键中,但我觉得这不是正确的方法。恕我直言,这种将 phpseclib 解释为已使用包的依赖项,它们彼此完全独立。

我现在开始认为这可能是服务器端 运行 时脚本失败的最终原因:包在其依赖项方面未正确安装,因此依赖项phpseclib 本身的需求没有被正确使用,因为 phpseclib 包本身被列为依赖项。因此,一些缺失的 base64 编码或类似的(paragonie 依赖 phpseclib 包,见上文)可能是导致问题的原因。这可能吗?消除这个原因;我需要知道如何在 plesk 服务器上通过 composer.json 通过 composer 正确安装扩展,而不触及以前以这种方式安装的软件包。关于如何做到这一点的任何想法?我还为此发布了一个单独的问题,以获取更多详细信息;你可以查看 it.

也可能导致问题的是当前 composer.json 文件需要的 php 版本低于 phpseclib atm 要求的版本 (php: > =5.6.1)。但同样,要改变这一点,我需要知道如何以正确的方式修改 composer.json 文件。

更新

我更新了 composer.json 文件,方法是将其内容从 plesk 服务器复制到我下载 composer 的本地环境。然后我通过命令提示符安装了 phpseclib 包,然后将生成的 composer.json 复制回 Plesk 服务器。我又遇到了完全相同的问题(而且 composer.json 内容也和以前一样)。求助..?

所以发生的事情是我检查了(在被阻止的 IP 等中)目标服务器上它侦听 SFTP 连接的端口。我注意到它 A) 没有在标准端口上侦听和 B) 阻止了标准端口上的传入连接请求。

奇怪的是,当从本地机器 运行 时,可以毫无问题地建立 SSH 连接,无需指定任何端口,因此始终使用标准端口。

在服务器上部署的脚本中,如果在服务器配置为侦听 SFTP 的端口上发出连接请求,则只能建立 SSH 连接。

更有趣的是,当我在其中指定非标准端口时,本地主机上的脚本 运行 以部署脚本失败的方式失败。

所以最后,不知道为什么会这样,但肯定都是通过测试确认的。