SSH的一些应用

以前发了一条tweet感慨,现在几乎就生活在ssh之中了。因为无论生活还是工作都离不开它,真是由衷的感谢那些设计和开发出这个伟大工具的程序员们。ssh最主要的功能就是把所有传输的数据加密,最初是的设计是为了替代传统明文传输的telnet、rlogin等程序,以避免密码嗅探攻击。而且ssh传输的数据还是经过压缩的,所以还能加快传输速度。

ssh是Secure Shell的简写,也就是说它能提供给你一个安全的shell,而保护这个安全shell的加密通道是通过端口转发(Port Forwarding)来完成的。这意味着ssh可以帮你把任意原本不安全的端口连接起来,提供给你安全的通道。安全的端口转发,这一点可以让ssh来完成很多有趣的应用。

SSH隧道代理

近期一个常见应用就是通过ssh本地端口转发数据包到国外主机,以穿透GFW访问被墙的网站。应用场景是这样的:

  • 你的国内主机,比如一台笔记本
  • 你拥有ssh权限的国外主机: forward.com,用户名是 user
  • 被墙的网站,比如Google主机: google.com

在笔记本上运行:

ssh -L localhost:1080:google.com:80 user@forward.com

这种方式称作本地转发(Local Forwarding),意思就是把本地端口1080通过foward.com转发到了Google服务器的80端口上,这样你访问本地的1080端口就和访问Google服务器一样了。

不过这只是在传输层的端口转发,因为被GFW的网站很多,所以一个个的转发未免太麻烦了。所幸ssh还提供应用层的端口转发(a local “dynamic” application-level port forwarding),这时候ssh就扮演一个sock代理服务器角色,目前支持sock4和sock5。下边就是我们平时常用的ssh tunnel的建立办法:

ssh -D 1080 user@forward.com

这样就在你的本地架设了一个sock proxy,然后你可以通过这个proxy来访问被墙的网站了,如果不希望打开一个shell,可以加上参数-N

如果你穿透NAT,有些防火墙看你半天不活动,会终止你的连接。不过你可以配置你的ssh客户端,让它定时在应用层发送一个keepalive的请求,这样能够保持你的sock proxy连接。比如每隔120秒发送一次,则在 ~/.ssh/config 中写入:

Host forward.com
ServerAliveInterval 120

如果你使用Firefox,推荐安装FoxyProxy插件,可以根据规则匹配被墙的网站地址。如果使用Chrome,可以使用Switchy插件。这样没有被墙的网站,你还是可以直接连接。这也是我觉得ssh tunnel比VPN更好用的地方。

如果你使用Windows主机,那就没有OpenSSH工具包,你需要去Putty网站下载一个plink,把它放到你的PATH目录,比如 C:\\Windows\\ ,然后在命令行中运行:

plink.exe -D 1080 user@foward.com

如果你讨厌Windows那个黑乎乎的cmd窗口,那么你可以另起一个进程,把这个proxy放在后台运行,写一段VB脚本,如果连接失败,plink进程会自行结束:

set ws=WScript.CreateObject("WScript.Shell")
ws.Run "plink.exe -N -D 1080 -pw password user@forward.com",0

SSH反向穿透

ssh既然可以把本地端口转发到远程端口,同样也可以把远程端口转发到本地端口(Remote Forwarding)。比如大家平时工作的时候都是在公司的NAT里,也许你是个勤劳的员工,回家之后还想在公司主机上干点活,一般公司都给大家配备一个VPN帐号,可以让你连接公司主机。但是,如果你有一台外网主机,你依然可以通过ssh端口转发来方向穿透防火墙,访问公司主机。应用场景如下:

  • 你的公司主机:desktop
  • 你可以访问的外网主机:myhost
  • 你在家使用的笔记本: notebook

首先你需要从公司主机发起一个ssh连接:

ssh -R localhost:9922:localhost:22 myhost

这里我写了两个localhost,其实是想加深大家对端口转发的理解,因为为了安全起见,侦听端口默认都是绑定在loopback上的,所以如果只是本地访问,第一个localhost总是可以省略的。这里说明一下,第一个localhost代表的是myhost的loopback地址,第二个localhost代表的是desktop的主机地址。

所以你下班回家,只要登录到myhost上,访问9922端口,就和访问desktop的22端口的效果是一样的。

SSH加密通道

X forwarding

SSH的密钥验证

首先在客户端运行命令,

$ ssh-keygen -t rsa

生成公钥文件 ~/.ssh/id_rsa.pub,然后复制该公钥到服务器端,保存成验证文件 ~/.ssh/authorized_keys

$ scp -p ~/.ssh/id_rsa.pub remote-server:~/.ssh/authorized_keys

SSH登录配置

为了省去输入用户名的麻烦,可以直接把用户名与对应主机保存在配置文件 ~/.ssh/config 中,可以使用通配符 ? 或者 *

ServerAliveInterval 180

Host xxx*
	User yyy

Host *
	Compression yes
	CompressionLevel 9
	KeepAlive yes

ssh远程文件系统

如果使用emacs编辑远程服务器脚本,可以使用内置的tramp,但体验不是很好,latency很大。一般可使用nfs挂载到本地再编辑。如果远程没有nfs服务,也可以使用sshfs 这个工具,这样服务器只要有ssh服务,就能够把服务器的目录mount到本地了。同时,可以使用上文提到的公钥验证办法,这样每次挂载的时候不需要输入密码。远程目录需使用绝对路径。

$ sshfs remote-host:/home/user local-directory