我try 使用SSH和Go连接到我的一个虚拟机.

ssh root@my_host

我输入密码,一切正常.

package main

import (
    "golang.org/x/crypto/ssh"
    "fmt"
)

func connectViaSsh(user, host string, password string) (*ssh.Client, *ssh.Session) {
    config := &ssh.ClientConfig{
        User: user,
        Auth: []ssh.AuthMethod{ssh.Password(password)},
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }

    client, err := ssh.Dial("tcp", host, config)
    fmt.Println(err)

    session, err := client.NewSession()
    fmt.Println(err)

    return client, session
}


func main() {
    client, _ := connectViaSsh("root", "host:22", "password")
    client.Close()
}

如果我运行它,它会返回一个错误:

ssh: handshake failed: ssh: unable to authenticate, attempted methods [none], no supported methods remain

有人知道是什么导致了这样的错误吗.在Python和shell中使用paramiko可以很好地工作,但在Go中失败.我有什么遗漏吗?

推荐答案

正如@JimB和@putu所指出的,我的服务器没有启用密码验证.

为了验证我是否使用verbose选项运行了ssh,并且它返回了所有支持的身份验证方法.

debug1 : Authentications that can continue: publickey,keyboard-interactive,hostbased

因此,我有两个 Select ,要么在服务器上启用密码身份验证,要么使用其他方法进行身份验证.

要启用密码身份验证,请连接到您的服务器并打开sshd配置文件,如下所示:

vi /etc/ssh/sshd_config

找到一行字,上面写着:PasswordAuthentication no

将其更改为"是",保存更改并重新启动sshd服务:service ssh restart

之后,密码验证方法开始按预期工作.

或者也可以使用其他方法,我决定try 键盘交互,这是用户使用ssh通过终端连接时通常使用的一种方法.

下面是执行此操作的代码片段,在远程服务器询问密码问题后发送密码:

package main
import (
    "bytes"
    "golang.org/x/crypto/ssh"
    "fmt"
)

func connectViaSsh(user, host string, password string) (*ssh.Client, *ssh.Session) {
    config := &ssh.ClientConfig{
        User: user,
        Auth: []ssh.AuthMethod{
            ssh.KeyboardInteractive(SshInteractive),
        },
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
    }
    client, err := ssh.Dial("tcp", host, config)
    fmt.Println(err)
    session, err := client.NewSession()
    fmt.Println(err)

    return client, session
}

func SshInteractive(user, instruction string, questions []string, echos []bool) (answers []string, err error) {
    answers = make([]string, len(questions))
    // The second parameter is unused
    for n, _ := range questions {
        answers[n] = "your_password"
    }

    return answers, nil
}

func main() {
    var b bytes.Buffer
    client, session := connectViaSsh("root", "host:22", "password")

    session.Stdout = &b
    session.Run("ls")
    fmt.Println(b.String())

    client.Close()
}

在我的例子中,服务器只会问一个问题,即密码,如果您的服务器问的问题比这个多,您需要构建一个完整的答案链来反馈.

Go相关问答推荐

在Go中根据命名空间/字符串生成UUID

在Mac中使用uname获取处理器体系 struct 时,在为AMD64构建Go二进制时出现错误结果

CURL和Postman HTTP POST工作,但Golang请求失败,状态为400

如何在VSCode中为特定的.go文件创建调试配置?

如何使redis池的等待超时

如何修复proxyconnect tcp:tls:第一条记录看起来不像tls握手

Cypher 查找(多个)最低 node

Kubo,来自 IpfsNode.Bootstrap 的无效内存地址或零指针取消引用

从单词中删除特殊字符

在两个单独的速率受限端点之间同步请求

如何处理 Go 的 firebase admin sdk 错误?

为什么时间很短.睡眠时间比基准测试中要求的(约 300 ns)长?

Golang BigInt 部门

如何从 Go 1.18 中的单个方法返回两种不同的具体类型?

显示作为服务帐户身份验证的谷歌日历事件 - Golang App

使用 xml.Name 将 xml 解组为 [] struct

为什么 Go 中的 maps.Keys() 将 map 类型指定为 M?

正则表达式处理数字签名的多个条目

(如何)我可以基于接口抽象地实现Stringer吗?

如何使用通用字段初始化匿名struct数组