【问题标题】:phpseclib - Can I connect using username, key and password (not a key passphrase)phpseclib - 我可以使用用户名、密钥和密码(不是密钥密码)进行连接吗
【发布时间】:2017-04-01 04:58:13
【问题描述】:

抱歉,如果我在文档中遗漏了这一点,但是否可以使用私钥和密码(不是我的私钥的密码)连接到 SFTP 服务器。

示例显示用户名/密码、用户名/密钥和用户名/密钥/密钥密码验证类型。

当通过命令行连接时,我会收到输入密码的提示...

user@x.x.x.x 的密码:

希望这个库可以处理这个问题吗?

否则是否有任何其他基于 PHP 的解决方案可能支持用户名/密钥和服务器密码身份验证?我在这里很灵活,可以根据需要安装模块。

编辑

感谢您到目前为止的帮助... 我试过你提到的Neubert,但这似乎不起作用。 为了验证连接到服务器所需的内容,我在命令行上对此进行了测试。
sftp key user@ip - 按预期提示输入密码
sftp user@ip - 提示输入密码,但输入正确时告诉我“已通过身份验证”部分成功”。

如果我可以使用密钥和密码进入,我认为目录和密钥的权限应该没问题。

我开始认为这个库不支持我需要的东西。

【问题讨论】:

  • 看到私钥的前 x 个字符仍然很有趣,直到 base64 编码的 blob。此外,查看 phpseclib 日志会很有趣。就像说“已通过部分成功验证”的 SSH 服务器还是客户端?您可以通过执行phpseclib.sourceforge.net/ssh/examples.html#logging 中描述的操作来获得它们。注意 define() 和 $ssh->getLog() 调用。

标签: php ssh passwords sftp phpseclib


【解决方案1】:

phpseclibsupports multi factor authentication。这是一个如何做到这一点的例子:

<?php
include('Net/SSH2.php');
include('Crypt/RSA.php')

$rsa = new Crypt_RSA();
$rsa->loadKey(file_get_contents('/path/to/key.pem'));

$ssh = new Net_SSH2('www.domain.tld');
if (!$ssh->login('username', 'pass1', $rsa)) {
    exit('Login failed');
}
// this does the same thing as the above
//if (!$ssh->login($username, 'pass1') && !$ssh->login('username', $rsa)) {
//    exit('Login failed');
//}

echo $ssh->exec('pwd');
echo $ssh->exec('ls -la');
?>

但请记住:很多人将受密码保护的私钥混淆为多因素(密码和公钥),而实际上并非如此。至少就 SSH 而言不是。

【讨论】:

  • 我认为问题在于多因素身份验证方法需要密码和密钥。执行上述代码只会在客户端验证您(为您提供两个单独的“部分成功”错误),而不是在远程 SFTP 服务器上。
  • 我什至不确定客户端身份验证是什么意思,哈哈。查看源执行 login() 两次,一次输入密码,一次输入密钥,将导致两个 NET_SSH2_MSG_USERAUTH_REQUEST 被发送到服务器。你试过了吗?我认为它会起作用。
  • 我只在客户端进行身份验证的意思是,如果login() 方法在每次调用时都与服务器建立新连接,那么您将有两个单独的连接,两者都“部分成功” ”。在客户端,我们知道密码和密钥是好的,因为它们都经过了部分验证,但在服务器上却不是,因为它们是在单独的连接中发送的。如果它没有创建新连接,我可能完全错了,你可以轻松地发送你拥有的密码,但是当我试图在我的问题中留给 OP 时,它需要编码。
  • 回答你的另一个问题,不,我没有尝试过,因为我没有这样配置的服务器来测试它。
  • 连接是在构造函数中创建的——而不是在 login() 方法中。 login() 只是重复使用相同的连接。
【解决方案2】:

@MartinPrikryl 的免责声明:此解决方案已过时,现在 phpseclib supports multi-factor authentication natively - 另请参阅 answer by @BoukeVersteegh@neubert


我在使用 phpseclib 的一个项目中遇到了同样的问题。我尝试了几个建议都无济于事,最后自己对库代码进行了一些研究。我最终修改了它,虽然不是很多。

在SSH2.php私有方法'_privatekey_login'(有key时从login方法调用),方法末尾有处理认证失败的代码。

extract(unpack('Ctype', $this->_string_shift($response, 1)));

switch ($type) {
   case NET_SSH2_MSG_USERAUTH_FAILURE:
      // either the login is bad or the server employs multi-factor authentication
      return false;
   case NET_SSH2_MSG_USERAUTH_SUCCESS:
      $this->bitmap |= NET_SSH2_MASK_LOGIN;
      return true;
}

输入一些日志后,我发现我从服务器返回的响应确实是“密码,键盘交互”。

我修改了所有登录方法(在 SFTP 和 SSH2 类中)以获取第二个密码,并将其一直传递给“_privatekey_login”方法。然后我将上面的部分更改为以下内容:

extract(unpack('Ctype', $this->_string_shift($response, 1)));

switch ($type) {
   case NET_SSH2_MSG_USERAUTH_FAILURE:
      // Possible multi-factor authentication.
      if ($password && $this->_keyboard_interactive_login($username, $password)) {
         $this->bitmap |= NET_SSH2_MASK_LOGIN;
         return true;
      }
      // the login is bad.
      return false;
   case NET_SSH2_MSG_USERAUTH_SUCCESS:
      $this->bitmap |= NET_SSH2_MASK_LOGIN;
      return true;
}

我从代码的另一部分复制了键盘交互调用,因此其中一些可能不是完全必要的。 虽然它可能不适用于所有服务器,但在我的情况下它工作得很好。

【讨论】:

    【解决方案3】:

    简单的回答:先用user+key登录,然后用user+pass登录。

    $host = 'ftp.example.com';
    $username = 'username';
    $password = 'secret';
    $key = new RSA();
    $key->load(file_get_contents('~/.ssh/private_key.pem'));
    
    $sftp = new SFTP($host);
    
    if ($sftp->login($username, $key) || $sftp->login($username, $secret)) {
        // success
    } else {
        // failed
    }
    

    是的,这已经提到过,但是长注释使它变得晦涩难懂,看起来很复杂。

    【讨论】:

    【解决方案4】:

    我决定删除我的另一个答案,因为事实证明我错了;您可以使用 SSH 进行多因素登录,但不是以标准方式。这些身份验证方法都不是原生的或内置于 openssh 的,因此没有标准的方法来解决它。大多数使用 Google Authenticator 提供一次性密码,但也有区别。根据this site 的建议,看起来它是通过在用户通过 SSH 服务器身份验证之后调用命令来完成的。在login() 方法中查看Net/SSH2.php 中的phpseclib 源代码,它具有以下代码:

    case NET_SSH2_MSG_USERAUTH_FAILURE:
        // can we use keyboard-interactive authentication?  if not then either the login is bad or the server employees
        // multi-factor authentication
        [...]
        return false;
    

    即使是 phpseclib 开发人员也意识到多因素身份验证是可能的,但由于缺乏标准,他们没有费心编写它。谷歌搜索你的错误代码

    部分成功验证

    表明这是您尝试连接的服务器的设置方式。如果您想编写特定于服务器设置的多因素身份验证,我不明白为什么这是不可能的。这是您需要编辑才能执行此操作的文件。

    【讨论】:

    • 试试这个:!$sftp->login() && !$sftp->login()。如果正在使用多因素身份验证并且密码身份验证返回 false,那么只要一种身份验证方法返回 true,就可以了。我已经更新了我的原始帖子。
    • @neubert 看到我对你的回答的评论
    【解决方案5】:

    您可以使用SSH2 bindings in PECL。它支持您提到的所有身份验证机制并且运行良好。

    【讨论】:

      最近更新 更多