乐趣区

聊一聊SSH

如果你对 NodeJs 系列感兴趣,欢迎关注微信公众号:前端神盾局 或 github NodeJs 系列文章
身为一枚合格的搬砖工程师,笔者经常需要登录服务器去查看日志或者部署应用,ssh 也随之成为最常用的 linux 命令之一。本文主要是对 SSH 的概念和用法做一些简单的梳理,大神请绕道。
什么是 SSH

SSH 是一种加密的网络传输协议,可在不安全的网络中为网络服务提供相对安全的传输环境。任何网络服务都可以通过 SSH 实现安全传输,但日常使用最多的还是远程登录服务器。
// 登录一台端口为 22,用户名为 username,ip 地址为 xx.xx.xx.xx 的远程主机
ssh -p 22 username@xx.xx.xx.xx
早先,互联网通信基本是裸奔的(明文传输),这使得内容很容易被窃取或监听。1995 年,芬兰学者 Tatu Ylonen 设计了 SSH 协议,将登录信息全部加密,成为互联网安全的一个基本解决方案,迅速在全世界获得推广,目前已经成为 Linux 系统的标准配置。
那 SSH 是如何实现加密的呢?整个过程如下:

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

当然这个过程并不是万无一失的,依旧存在“中间人攻击”的风险,具体可参考阮一峰老师的文章:SSH 原理与运用(一):远程登录
本地端口转发
在实际项目中,笔者经常遇到这样的一种情况:由于测试环境中数据库和开发数据库的没有同步,导致笔者无法很好的复现 bug。
那有同学问,为什么不直接连到测试服务器呢?原因很简单,连不上。测试环境数据库服务器并没有对外开放。
所以刚开始的时候,笔者为此相当苦恼,每次需要验证数据的时候,都要先把测试环境中数据导出再导入到开发环境中,这样一趟下来十几分钟过去了 …
那有什么方法可以连到测试数据库呢?
有的,使用 ssh 本地端口转发
先来描述一下场景,host1(106.xx.xxx.xx)是远程主机,是可以对外访问的;host2 是内网主机(10.xx.xxx.x 安装了 mongo 数据库),只能通过 host1 访问,无法连接外网。
我们需要两个步骤实现本地端口转发
创建本地服务器
const http = require(‘http’);
const server = http.createServer(function(req,res){});
server.listen(5000);
这里我们创建了一个端口为 5000 的本地服务
ssh 转发
ssh -L 5000:10.xx.xxx.x:27017 username@106.xx.xxx.xx
命令中的 L 参数一共接受三个值,分别是 ” 本地端口: 目标主机: 目标主机端口 ”,它们之间用冒号分隔。这条命令的意思,就是指定 SSH 绑定本地端口 5000,然后指定 host1 将所有的数据,转发到目标主机 host2 的 27017 端口。
运行命令,随后我们在浏览器中打开 http://localhost:5000,可以看到页面显示如下:
It looks like you are trying to access MongoDB over HTTP on the native driver port.
这表示我们连接成功~
ssh 命令挺长的,还有各种 ip 地址 … 有没有简化版呢?
好吧~我们可以使用 tunnel-ssh 改造一下
const tunnel = require(‘tunnel-ssh’);
const server = tunnel({
keepAlive: true,
// host1
host: ‘106.xx.xxx.xx’,
username: ‘superTerrorist’,
password: ‘xxxx’,
port: 22,
// 内网主机 host2
dstHost: ’10.xx.xxx.x’,
dstPort: 27017,
// 本地端口
localPort: 5000,
},async function(error,server){
if(error){
console.log(error);
return;
}
console.log(‘ssh tunnel connected’);
});
这里我们使用了第三方包 tunnel-ssh 实现了本地转发的功能,每次我们只要使用 node script.js 即可,这比使用 ssh 清爽多了。如果各位同学还有更好的方法,欢迎在此留言讨论
参考

Secure Shell
鸟哥的 Linux 私房菜
SSH 原理与运用

退出移动版