我尝试使用SSH和Go连接到我的一台虚拟机。 如果我这样做,它通过命令行完美地工作:
ssh root@my_host
我输入密码,一切正常。 我试着去Go,这是我的代码:
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中使用paramiko并且在shell中运行得很好但在Go中失败。我有什么遗失的吗?
答案 0 :(得分:9)
正如@JimB和@putu指出的那样,我的服务器没有启用密码验证。 要验证我使用详细选项运行ssh,它会返回所有支持的身份验证方法。在我的情况下,结果证明是:
debug1: Authentications that can continue: publickey,keyboard-interactive,hostbased
所以我有两个选项,要么在服务器上启用密码验证,要么使用其他方法进行身份验证。
要启用密码身份验证,请连接到您的服务器并打开sshd配置文件,如下所示:
vi/etc/ssh/sshd_config
查找说法: PasswordAuthentication no
将其更改为是,保存更改并重新启动sshd服务:service ssh restart
之后,密码验证方法开始按预期工作。 或者可以使用其他方法,我决定尝试键盘交互,一个用户通常使用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()
}
在我的情况下,服务器只询问一个密码问题,如果您的服务器要求的数量超过了您需要构建整个回馈链以进行反馈的话。