本地主机上的 PHPSeclib 公钥认证成功;部署失败
Posted
技术标签:
【中文标题】本地主机上的 PHPSeclib 公钥认证成功;部署失败【英文标题】:PHPSeclib Public Key Authentication Successful on Localhost; Failing when deployed 【发布时间】:2021-12-21 08:29:48 【问题描述】:我创建了一个脚本,它使用phpseclib
扩展名连接到服务器,使用公钥认证(如您所见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;
我生成了三个密钥对,使用它们运行了 localhost 和服务器-客户端测试,我总是得到上面显示的内容。当我回显它时,我肯定得到了密钥,不用担心它不是加密的 OpenSSH 私钥,这不是原因(phpseclib
不支持),然后在 localhost 上也会失败(这我已经测试过了)。
所以看起来它在服务器上的公钥身份验证步骤上失败了,尽管我使用的是完全相同的脚本,虽然我在回显检索到的密钥时得到了完全正确的密钥,但也在服务器端。
然后我检查了如果我更改密钥的单个字符会发生什么;如果这重现了上面显示的 SSH - 日志,但没有。如果我这样做,脚本会在记录任何内容之前中断,抛出 phpseclib3\Exception\NoKeyLoadedException: Unable to read key
异常。
由此我得出结论,唯一的问题可能是密钥在发送到服务器之前以某种错误的方式编码,并且服务器因此误解了密钥。
考虑到这一点,我发现phpseclib
根据this 需要paragonie
包,并且paragonie
的phpseclibs
依赖项之一执行一些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
包,见上文)可能会导致问题。这可能吗?消除这个原因;我需要知道如何通过 Composer 通过 composer.json
在 plesk 服务器上正确安装扩展,而不接触以前以这种方式安装的包。关于如何做到这一点的任何想法?我还为此发布了一个单独的问题,以获取更多详细信息;您可以查看it。
还可能导致问题的是当前的composer.json
文件需要低于phpseclib
atm 所需的php 版本(php:> = 5.6.1)。但同样,要改变这一点,我需要知道如何以正确的方式修改 composer.json
文件。
更新
我已经更新了composer.json
文件,方法是将其内容从 plesk 服务器复制到我下载作曲家的本地环境中。然后我通过命令提示符安装了phpseclib
包,然后将生成的composer.json
复制回Plesk 服务器。我又遇到了完全相同的问题(此外还有与以前相同的composer.json
内容)。帮助..?
【问题讨论】:
向我们展示两台机器上的$sftp->getLog()
+ 你能从服务器使用任何命令行/GUI SFTP 客户端登录吗?
所以请尝试!!
如果您使用的是 OpenSSH,我会尝试以调试模式重新启动 SSH 服务器并查看得到的输出。例如。 sudo /usr/sbin/sshd -ddd -p2222
。除此之外......到目前为止,这里的任何人都知道SSH服务器可能会丢弃密钥,因为它不是来自列入白名单的IP地址。通常你会通过使用 iptables 或类似的东西来限制 IP 地址,这会阻止你甚至连接,但是如果你甚至使用 OpenSSH 并且谁知道其他 SSH 服务器的功能是什么,那么 tbh idk
如果您更愿意与 phpseclib 作者分享数据,我建议您给他发电子邮件。 terrafrost@php.net。该电子邮件位于 phpseclib 源代码中:github.com/phpseclib/phpseclib/blob/3.0.11/phpseclib/Net/… 也就是说,我对此的看法是:问题很可能与 phpseclib 无关,而与您的服务器有关。最终,是您的服务器拒绝登录请求,并且正如您所指出的,您可以在本地毫无问题地登录。我们知道您在客户端使用什么,但对服务器知之甚少。
"当您谈论“服务器”时,您指的是客户端服务器,对吗?”是的,我猜。我想我们最终拥有 3 台计算机。 A 是您的本地计算机,B 是您的产品服务器,C 是您尝试通过 SSH 连接的服务器(我猜是“客户端服务器”)。您可以从 A 连接到 C,但不能从 B 连接。如果它是“客户端服务器”,我猜您将无法通过 sudo /usr/sbin/sshd -ddd -p2222
获取日志。在那种情况下,我会跟进他们。就像“我可以从我的 localhost 但不能从 prod 连接到您的服务器;每个 IP 地址都是 ...”
【参考方案1】:
所以发生的事情是我检查了目标服务器上的(在被阻止的 IP 等中)它在哪个端口上侦听 SFTP 连接。而且我注意到它 A) 没有在标准端口上侦听 B) 阻止了标准端口上的传入连接请求。
奇怪的是,当从本地机器运行时,SSH 连接可以毫无问题地建立,无需指定任何端口,因此一直使用标准端口。
在服务器上部署的脚本中,如果连接请求是在服务器配置为侦听 SFTP 的端口上发出的,则可以独占建立 SSH 连接。
更有趣的是,在 localhost 上运行的脚本失败的方式与我在其中指定非标准端口时部署的脚本失败的方式相同。
所以最后,不知道为什么会发生这种情况,但肯定都是通过测试确认的。
【讨论】:
以上是关于本地主机上的 PHPSeclib 公钥认证成功;部署失败的主要内容,如果未能解决你的问题,请参考以下文章