在Go语言中,golang.org/x/crypto/ssh
是一个官方维护的第三方库,用于实现 SSH 客户端和服务器功能。本文我们将学习如何使用该库建立 SSH 连接、执行远程命令、模拟终端交互等常见操作。
一、安装 golang.org/x/crypto/ssh
首先,确保你的 Go 环境已安装。然后,通过以下命令安装 SSH 库:
go get -u golang.org/x/crypto/ssh
二、配置 SSH 客户端
使用 ssh.ClientConfig
结构体配置 SSH 客户端:
package main
import (
"fmt"
"golang.org/x/crypto/ssh"
"log"
)
func createSSHClient(user, password, host string, port int) (*ssh.Client, error) {
config := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
ssh.Password(password),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", host, port), config)
if err != nil {
return nil, err
}
return client, nil
}
在上述代码中,HostKeyCallback
使用 ssh.InsecureIgnoreHostKey()
忽略主机密钥验证,适用于开发和测试环境。在生产环境中,应使用更安全的方式验证主机密钥。
三、执行远程命令
通过 client.NewSession()
创建会话,并使用 session.Run()
执行命令:
func runCommand(client *ssh.Client, command string) (string, error) {
session, err := client.NewSession()
if err != nil {
return "", err
}
defer session.Close()
output, err := session.CombinedOutput(command)
if err != nil {
return "", err
}
return string(output), nil
}
CombinedOutput
方法返回命令的标准输出和标准错误输出。
四、模拟终端交互
如果需要模拟终端交互(例如执行 top
命令),可以使用伪终端(PTY):
func startInteractiveShell(client *ssh.Client) error {
session, err := client.NewSession()
if err != nil {
return err
}
defer session.Close()
modes := ssh.TerminalModes{
ssh.ECHO: 0,
ssh.TTY_OP_ISPEED: 14400,
ssh.TTY_OP_OSPEED: 14400,
}
termWidth, termHeight, err := term.GetSize(int(os.Stdout.Fd()))
if err != nil {
return err
}
if err := session.RequestPty("xterm", termHeight, termWidth, modes); err != nil {
return err
}
session.Stdin = os.Stdin
session.Stdout = os.Stdout
session.Stderr = os.Stderr
if err := session.Shell(); err != nil {
return err
}
return session.Wait()
}
上述代码请求一个伪终端,并将标准输入、输出和错误输出绑定到本地终端,实现交互式操作。
五、使用公钥认证
为了提高安全性,可以使用公钥认证替代密码认证:
func createSSHClientWithKey(user, keyPath, host string, port int) (*ssh.Client, error) {
key, err := ioutil.ReadFile(keyPath)
if err != nil {
return nil, err
}
signer, err := ssh.ParsePrivateKey(key)
if err != nil {
return nil, err
}
config := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}
client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", host, port), config)
if err != nil {
return nil, err
}
return client, nil
}
在上述代码中,keyPath
是私钥文件的路径。ssh.PublicKeys(signer)
用于创建公钥认证方法。
六、处理主机密钥验证
在生产环境中,建议验证服务器的主机密钥,以防止中间人攻击:
func verifyHostKey(host string, remote net.Addr, key ssh.PublicKey) error {
// 实现主机密钥验证逻辑
return nil
}
可以通过 ssh.FixedHostKey()
或自定义回调函数来实现主机密钥验证。
七、完整示例
以下是一个完整的示例,演示如何使用密码认证连接 SSH 服务器并执行命令:
package main
import (
"fmt"
"golang.org/x/crypto/ssh"
"log"
)
func main() {
client, err := createSSHClient("user", "password", "example.com", 22)
if err != nil {
log.Fatalf("Failed to create client: %v", err)
}
defer client.Close()
output, err := runCommand(client, "ls -al")
if err != nil {
log.Fatalf("Failed to run command: %v", err)
}
fmt.Println(output)
}

声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 恋水无意
腾讯云开发者社区:孟斯特
—