go语言实现ssh打隧道

栏目: Go · 发布时间: 5年前

内容简介:使用ssh打个隧道,是我一直想做的事情。出发点是:在公司内部经常有些机器访问不到,只能通过公司提供的开发机,但是开发机我们可以在内网访问到,这个SSH是一种网络协议,用于计算机之间的加密登录,流程大致是:上面这个过程中很容易受到攻击的就是第一步,我们怎么知道收到的公钥是真正的主机的,体现在实际登陆中,就是会出现:

使用ssh打个隧道,是我一直想做的事情。出发点是:在公司内部经常有些机器访问不到,只能通过公司提供的开发机,但是开发机我们可以在内网访问到,这个

基础知识

SSH是一种网络协议,用于计算机之间的加密登录,流程大致是:

  1. 远程主机收到用户的登录请求,把自己的公钥发给用户。
  2. 用户使用这个公钥,将登录密码加密后,发送回来。
  3. 远程主机用自己的私钥,解密登录密码,如果密码正确,就同意用户登录。

上面这个过程中很容易受到攻击的就是第一步,我们怎么知道收到的公钥是真正的主机的,体现在实际登陆中,就是会出现:

 $ 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 认证的方式有两种:

  1. 用户名 + 证书
  2. 用户名 + 密码

下面我们来看 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


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Agile Web Application Development with Yii 1.1 and PHP5

Agile Web Application Development with Yii 1.1 and PHP5

Jeffrey Winesett / Packt Publishing / 2010-08-27

In order to understand the framework in the context of a real-world application, we need to build something that will more closely resemble the types of applications web developers actually have to bu......一起来看看 《Agile Web Application Development with Yii 1.1 and PHP5》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具