SSH(Secure Shell)是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境。(更多详情可参阅维基百科 https://zh.wikipedia.org/wiki/Secure_Shell)
SSH协议基于的传输层协议为TCP,默认端口22。(与Telnet的区别,Telnet明文传输内容故不安全。默认端口FTP 2一、SSH 2二、Telnet 23)html
大多数现代操做系统(包括macOS、大部分Linux、OpenBSD、FreeBSD、Solaris等系统)都提供了SSH协议的实现程序,但Windows系统未自带SSH程序。Windows用户可使用Cygwin来创建SSH服务。(补注:从 Win10 1809 和 Windows Server 2019 开始 Windows 已支持 OpenSSH Server)linux
SSH命令参数说明:Linux下可经过 man ssh 命令查看(中文翻译版可参阅 http://linux.51yip.com/search/ssh)
web
先验知识算法
ssh登陆须要用到公钥、秘钥,它们用于对文本内容进行加密或解密。一般用RSA加密方式,其是一种对称加密,由公钥加密的内容私钥可解密、由私钥加密的内容公钥也可解密。公钥能够对外公开,私钥则不能。关于RSA加密可参阅:RSA算法原理-阮一峰浏览器
经过ssh登陆远程主机一般有两种登陆方式:安全
一、输密码登陆:每次登陆都要输密码。内部原理:登陆时服务端发送服务端本身的公钥给客户端,客户端用该公钥加密密码并发送到服务端,服务端用对应的私钥解密,检查密码是否正确以肯定是否登陆成功。bash
第一次登陆时会警告公钥是否可信任,以防止中间人攻击返回的是中间人的公钥,若用户确认信任之则公钥会保存到客户端的$HOME/.ssh/known_hosts文件里,之后再登陆就不会有警告了。服务器
二、秘钥登陆(免密码登陆):预先配置好秘钥,以后每次登陆无需输密码。方法是在一台机器上生成公钥/私钥对并将其中一个秘钥放到另外一个机器上。有两种:网络
2.一、公钥登陆:事先将客户端的公钥放到服务端上(本质上至关于配置免密登陆白名单)。内部原理:登陆时服务端发送一个随机字符串给客户端,客户端用本身的私钥加密并发送到服务端,服务端根据是否有事先存储的公钥能进行解密以肯定是否登陆成功。并发
2.二、私钥登陆:事先将服务端的私钥放到客户端上,每次登陆时须要指定私钥,可见此时私钥至关于服务端的临时密码。
前一种方式须要对服务端进行配置,若要免密登陆的客户端不少,则须要频繁修改服务端配置;后一种能够避免频繁更改服务端,但比较不安全由于私钥是不宜外泄的,这种模式只要有私钥的人就能访问服务器,可是例如阿里云服务器就是这种访问方式。
这里介绍公钥登陆的配置方法(假设机器A登陆机器B须要密码,但不想每次登陆都需输密码):
一、A上生成密钥对: ssh-keygen ,会在当前用户目录 ~/.ssh/ 下生成 id_rsa、id_rsa.pub 两个文件,里面内容分别为私钥、公钥
二、将公钥(id_rsa.pub里的内容)追加到到B上 ~/.ssh/authorized_keys 文件中,文件不存在则新建。也可在A上经过命令完成该效果: ssh-copy-id -i ~/.ssh/id_rsa.pub <username of B>@<host of B>
三、重启B上的ssh服务: sudo service sshd restart
四、以后若还不行,可检查B上的/etc/ssh/sshd_config文件,确认以下内容没被注释:
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
参考资料:http://www.ruanyifeng.com/blog/2011/12/ssh_remote_login.html
可经过SSH执行远程命令而不须要登陆远程主机,示例:(更多可参阅:http://www.javashuo.com/article/p-ofwmixvl-dg.html)
# 主要命令格式
ssh user@10.5.6.47 "ls /home; pwd " # 执行基本命令,可有多个 ssh -t user@10.5.6.47 " top " # 对于须要交互(须要tty)的命令,经过ssh远程执行时不会为此会话分配tty,故ssh当即退出远程主机从而须要交互的命令当即结束。经过 -t 参数显示声明须要为会话分配tty以解决之 ssh user@10.5.6.47 " bash -s " < test.sh helloworld # 远程执行本地主机上的脚本,参数为往脚本传的参数 ssh user@10.5.6.47 /home/user/test.sh helloworld # 远程执行远程主机上的脚本,参数为往该脚本传的参数
# 其余trick示例
cd && tar czv src | ssh user@host 'tar xz' # 将$HOME/src/目录下面的全部文件,复制到远程主机的$HOME/src/目录
ssh user@host 'tar cz src' | tar xzv # 将远程主机$HOME/src/目录下面的全部文件,复制到用户的当前目录
SSH是安全的,会自动加密和解密全部 SSH 客户端与服务端之间的网络数据。此外,SSH 还提供了一个很是有用的功能——端口转发:它可以将其余 TCP 端口的网络数据经过 SSH 链接来转发,并自动提供了相应的加密及解密服务。因 SSH 为其余 TCP 链接提供了一个安全的通道来进行传输,故也被称做SSH隧道(SSH Tunnel)。例如,Telnet,SMTP,LDAP 这些 TCP 应用均可以从中得益,避免了用户名,密码以及隐私信息的明文传输。而与此同时,若是工做环境中的防火墙限制了一些网络端口的使用但容许 SSH 链接,则也可经过 TCP 端口转发来使用 SSH 进行通讯。
总的来讲,SSH 端口转发能提供两大功能:
一、加密SSH Client与SSH Server间传输的数据
二、突破防火墙限制以间接完成一些以前没法创建的 TCP 链接
从效果上看,端口转发至关因而反向代理。
SSH端口转发为没法直接任意互通但能经过SSH访问的两个网络或机器间提供了一个互通的桥梁。分为 本地端口转发、远程端口转发、动态端口转发三种。
这里设想一种场景,假设有机器A、B、C、D,其间关系为:A、B间可互通,C、D间可互通,AB与CD间不能自由互通(因设置了防火墙、白名单等,只有B能经过SSH访问C、反之则不可。(想象AB、CD分别在不通的网段、两个网段间只有B能经过SSH访问到C且C只对B开放SSH的22端口)。
命令: ssh -L <forward port>:<target host>:<target port> <SSH server addr>
功能:将对SSH Client所在机器<forward port>端口的请求转发到指定机器的指定端口(即 <target host>:<target port> )
原理:SSH Client所在机器分配一个 socket 监听 <forward port> 端口,一旦此端口上有了链接,该链接就经安全通道转发出去,同时SSH server所在机器和 <target host>:<target port> 创建链接。(请求的内部走向是SSH Client -> SSH Server -> 目标机,返回时原路返回)
应用场景:使得“内网”(SSH Client所在的)能访问到不能直接访问的其余"网络"
示例:假设D上有个web服务监听8080端口,显然,A、B都没法直接访问到该服务但C能够。而B能够经过SSH访问C,此时在B上执行: ssh -g -fN -L 1000:hostD:8080 hostCSshAddr ,则A或B经过访问B的1000端口就能访问到D的web服务(内部走向是B -> C -> D)。
若没有-g参数,则A访问不了B的1000端口,只有B本身能够。
若web服务在SSH server上(即目标主机与SSH服务端是同一个),则命令可简为: ssh -g -fN -L 1000:localhost:8080 hostCSshAddr ,可见这里的localhost是相对于SSH server而言的。
(与本地端口转发几乎同样,只不过转发端口在SSH Server且请求的内部走向相反)
命令: ssh -R <forward port>:<target host>:<target port> <SSH server addr> ,注:不支持 -g 参数
功能:将对SSH Server所在机器<forward port>端口的请求转发到指定机器的指定端口(即 <target host>:<target port> )
原理:SSH Server所在机器分配一个 socket 监听 <forward port> 端口,一旦此端口上有了链接,该链接就经安全通道转发出去,同时SSH Client所在机器和 <target host>:<target port> 创建链接。(请求的内部走向是SSH Server -> SSH Client -> 目标机,返回时原路返回)
应用场景:使得"外网"能访问到"内网"(SSH Client所在的)
示例:若上述web服务在A,显然,C、D没法直接访问该服务但B能够。而B能够经过SSH访问C,此时在B上执行: ssh -fN -R 1000:hostA:8080 hostCSshAddr ,则C可经过访问其1000端口就能访问到A的web服务(内部走向是C -> B -> A)。
注:远程端口转发不支持-g参数故这里没法像本地端口转发那样经过 -g 参数让D能访问到A的web服务。解决:在SSH Server(即C)的/etc/ssh/sshd_config添加一行并重启SSH服务: GatewayPorts yes
命令: ssh -D <foward port> <SSH server addr> ,可用参数与本地端口转发的同样
功能及原理:与本地端口转发同样,将对SSH Client所在机器<forward port>端口的请求转发到SSH Server上,只不过设置时不用指定目的机器的host和port。SSH Client成为一个反向代理,应用设置代理为SSH Client后,应用发起请求时请求的内部走向也是SSH Client -> SSH Server -> 目标机,收到SSH Client转发来的请求时SSH Server会与该请求的目标机链接。SSH 动态端口转发是经过 Socks 协议实现的,建立动态端口转发时 SSH 服务器就相似一个 Socks 代理服务器,因此这种转发方式也叫 Socks 转发。
应用场景:
做为代理:把全部请求都转发到目的机,以突破防火墙等限制。
提升安全性:让那些不加密的网络链接,所有改走SSH链接,从而提升安全性。
示例: 做为反向代理——在本节首所述场景下,在B执行: ssh -g -fN -D 1000 hostCSshAddr ,至关于启动了个反向代理服务。以后在A或B上设置Sockets代理(如在浏览器设置Sockets代理),地址为 hostB:1000,则C、D上的服务均能被A或B访问到。如A访问服务hostD:8080,请求会经过 SSH Client B -> SSH Server C -> hostD:8080,由C完成对D的请求后原路返回结果。
注:
SSH 端口转发是经过 SSH 链接创建起来的,故必须保持这个 SSH 链接以使端口转发保持生效。一旦关闭了此链接,相应的端口转发也会随之关闭。
只能在创建 SSH 链接的同时建立端口转发,而不能给一个已经存在的 SSH 链接增长端口转发。
参考资料:
http://www.javashuo.com/article/p-sibzutlz-ke.html ssh端口转发
http://www.ruanyifeng.com/blog/2011/12/ssh_port_forwarding.html