内容简介:使用ssh打个隧道,是我一直想做的事情。出发点是:在公司内部经常有些机器访问不到,只能通过公司提供的开发机,但是开发机我们可以在内网访问到,这个SSH是一种网络协议,用于计算机之间的加密登录,流程大致是:上面这个过程中很容易受到攻击的就是第一步,我们怎么知道收到的公钥是真正的主机的,体现在实际登陆中,就是会出现:
使用ssh打个隧道,是我一直想做的事情。出发点是:在公司内部经常有些机器访问不到,只能通过公司提供的开发机,但是开发机我们可以在内网访问到,这个
基础知识
SSH是一种网络协议,用于计算机之间的加密登录,流程大致是:
- 远程主机收到用户的登录请求,把自己的公钥发给用户。
- 用户使用这个公钥,将登录密码加密后,发送回来。
- 远程主机用自己的私钥,解密登录密码,如果密码正确,就同意用户登录。
上面这个过程中很容易受到攻击的就是第一步,我们怎么知道收到的公钥是真正的主机的,体现在实际登陆中,就是会出现:
$ ssh user@host The authenticity of host 'host (12.18.429.21)' can't be established. RSA key fingerprint is 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d. Are you sure you want to continue connecting (yes/no)? 复制代码
此处 RSA key fingerprint
就是对128公钥的MD5签名,当输入yes后,就会保存到$HOME/.ssh/known_hosts,说明是对公钥的认可。
解决了信任问题后,下一个不好的是每次都需要输入密码,于是就有了 公钥登陆 ,就是用户将自己的公钥储存在远程主机上。登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录shell,不再要求密码。
所以总结起来 ssh 认证的方式有两种:
- 用户名 + 证书
- 用户名 + 密码
下面我们来看 go 中相应的操作方法
golang 实现 ssh client
go get -u golang.org/x/crypto/... 复制代码
先来说2种认证方式,显示密码,通过 ssh.Password
来传入密码
sshConfig := &ssh.ClientConfig{ User: "your_user_name", Auth: []ssh.AuthMethod{ ssh.Password("your_password") }, } 复制代码
第二种是证书的方式,这又细分为两种,一种是我们直接读取自己的私钥,另一种是从ssh-agent读取,ssh-agent是用来帮助我们管理私钥的程序,它的出现主要是为了解决当我们访问不同的主机使用不同的私钥-公钥对,同时解决如果设置了私钥的密码,需要每次都手动设置的问题。 ps:ssh-agent的管理
eval `ssh-agent` 启动agent代理 ssh-add /path/to/key/key_name 添加指定私钥 ssh-agent -k 关闭 agent ssh-add -l 查看代理中私钥 ssh-add -L 查看代理中私钥对应的公钥 ssh-add -d /path/to/key/key_name 移除指定私钥 ssh-add -D 删除管理的所有私钥 复制代码
从文件读取
func PublicKeyFile(file string) ssh.AuthMethod { buffer, err := ioutil.ReadFile(file) if err != nil { return nil } key, err := ssh.ParsePrivateKey(buffer) if err != nil { return nil } return ssh.PublicKeys(key) } 复制代码
从 ssh-agent 读取
func SSHAgent() ssh.AuthMethod { if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil { return ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers) } return nil } 复制代码
client生成
当我们有了认证方式后,下面就是生成ssh-client
sshClient, err := ssh.Dial("tcp", "host:port", sshConfig) if err != nil { return nil, fmt.Errorf("Failed to dial: %s", err) } 复制代码
建立连接后,我们要创建一个命令执行的session,一个session就是一次命令执行,在开始执行命令之前,我们还要建立一个伪终端,方便输入输出
modes := ssh.TerminalModes{ ssh.ECHO: 0, // disable echoing ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud } if err := session.RequestPty("xterm", 80, 40, modes); err != nil { session.Close() return nil, fmt.Errorf("request for pseudo terminal failed: %s", err) } 复制代码
再然后我们就可以开始执行代码,完整代码见 ssh_client
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。