SSH入门
概述
SSH是Linux系统的登录工具,现在广泛用于服务器登录和各种加密通信。
SSH的软件架构是服务器-客户端模式(Server - Client)。在这个架构中,SSH软件分成两个部分:向服务器发出请求的部分,称为客户端(client),OpenSSH的实现为ssh;接收客户端发出的请求的部分,称为服务器(server),OpenSSH的实现为sshd。
ssh客户端
ssh登录
~/.ssh
文件夹下的id_rsa
, id_dsa
, id_ecdsa
, id_ecdsa_sk
, id_ed25519
, id_ed25519_sk
, id_xmss
等密钥。
|
|
此外还可以使用ssh-add
命令来把密钥添加到高速缓存中,从而不需要指定对应的密钥,提升登录速度。
使用ssh-add
之前是需要开启ssh-agent的,很多操作系统默认是不开启的,可以通过下面的方式开启:
|
|
主要包含以下几个命令:
- 添加密钥到缓存
1 2
# 添加~/.ssh/id_dsa ssh-add ~/.ssh/id_dsa
- 列出所有添加的密钥
1
ssh-add -l
配置了上述ssh-add
之后,应该能够顺利的通过下面的命令克隆代码
|
|
相比与这种方式,在~/.ssh/config
文件中配置可能会更为简单有效,配置示例如下:
|
|
ssh端口转发
SSH 除了登录服务器,还可以作为加密通信的中介,充当两台服务器之间的通信加密跳板,使得原本不加密的通信变成加密通信。这个功能称为端口转发(port forwarding),又称 SSH 隧道(tunnel)。
端口转发有两个主要作用:
- 将不加密的数据放在 SSH 安全连接里面传输,使得原本不安全的网络服务增加了安全性,比如通过端口转发访问 Telnet、FTP 等明文服务,数据传输就都会加密。
- 作为数据通信的加密跳板,绕过网络防火墙。
术语
- Client Host:也就是我们运行
ssh
命令定义隧道(tunnel)的一端 - Tunnel Host:其实就是建立隧道连接的一端
- Ingress:我们称初始化的那一端,或者进入的那一端,或者监听的那一端为ingress
- Egress:退出、终止的一端为egress
动态转发
动态转发指的是,本机与 SSH 服务器之间创建了一个加密连接,然后本机内部针对某个端口的通信,都通过这个加密连接转发。它的一个使用场景就是,访问所有外部网站,都通过 SSH 转发。动态转发需要把本地端口绑定到 SSH 服务器。至于 SSH 服务器要去访问哪一个网站,完全是动态的,取决于原始通信,所以叫做动态转发。
|
|
上面命令中,-D
表示动态转发,local-port
是本地端口,tunnel-host
是 SSH 服务器,-N
表示这个 SSH 连接只进行端口转发,不登录远程 Shell,不能执行远程命令,只能充当隧道。
如果经常使用动态转发,可以将设置写入 SSH 客户端的用户个人配置文件(~/.ssh/config
)。
|
|
将本机的9999
端口都转发到guopai16(10.176.22.16)
|
|
注意,这种转发采用了 SOCKS5
协议。访问外部网站时,需要把 HTTP
请求转成 SOCKS5
协议,才能把本地端口的请求转发出去。
下面是 SSH 隧道建立后的一个使用实例:
|
|
本地转发
本地转发(local forwarding)指的是,SSH 服务器作为中介的跳板机,建立本地计算机与特定目标网站之间的加密连接。本地转发是在本地计算机的 SSH 客户端建立的转发规则。
它会指定一个本地端口(local-port),所有发向那个端口的请求,都会转发到 SSH 跳板机(tunnel-host),然后 SSH 跳板机作为中介,将收到的请求发到目标服务器(target-host)的目标端口(target-port)。
|
|
上面命令中,-L
参数表示本地转发,local-port
是本地端口,target-host
是你想要访问的目标服务器,target-port
是目标服务器的端口,tunnel-host
是 SSH 跳板机。
还可以添加-g
参数,表示将本地当作网关,其他可以访问本机的机器可以通过local-port
访问到target-port
。
注意,本地端口转发采用 HTTP
协议,不用转成 SOCKS5
协议。
如果经常使用本地转发,可以将设置写入 SSH 客户端的用户个人配置文件(~/.ssh/config
)。
|
|
现在有一台 SSH 跳板机guopai16
,我们想要通过这台机器,在本地9999
端口与目标网站www.baidu.com
的80
端口之间建立 SSH 隧道,就可以写成下面这样。
|
|
接着我们在本地访问localhost:9999/
,在guopai16
上抓取80
端口的流量如下:
|
|
则别的机器可以通过当前本机的ip:8000访问10.176.22.11:8000。
远程转发
远程转发指的是在远程 SSH 服务器建立的转发规则。 它跟本地转发正好反过来。建立本地计算机到远程计算机的 SSH 隧道以后,本地转发是通过本地计算机访问远程计算机,而远程转发则是通过远程计算机访问本地计算机。它的命令格式如下。
|
|
上面命令中,-R
参数表示远程端口转发,remote-port
是远程计算机的端口,target-host
和target-port
是目标服务器及其端口,remotehost
是远程计算机。
如果经常执行远程端口转发,可以将设置写入 SSH 客户端的用户个人配置文件(~/.ssh/config
)。
|
|
内网某台服务器localhost
在 80
端口开了一个服务,可以通过远程转发将这个 80
端口,映射到具有公网 IP 地址的my.public.server
服务器的 8080
端口,使得访问my.public.server:8080
这个地址,就可以访问到那台内网服务器的 80
端口。
|
|
ssh-keygen
生成密钥
密钥登录时,首先需要生成公钥和私钥。OpenSSH 提供了一个工具程序ssh-keygen
命令,用来生成密钥。
ssh-keygen
常用选项如下所示:
-b
指定密钥的二进制位数
这个参数值越大,密钥就越不容易破解,但是加密解密的计算开销也会加大。一般来说,-b
至少应该是1024
,更安全一些可以设为2048
或者更高。
-C
指定密钥的注释
格式为username@host
。下面命令生成一个4096
位 RSA 加密算法的密钥对,并且给出了用户名和主机名。
|
|
-f
指定生成的私钥文件
|
|
-F
检查某个主机名是否在known_hosts
文件里面
|
|
-N
指定私钥的密码(passphrase)
|
|
-p
重新指定私钥的密码(passphrase)
-p
参数用于重新指定私钥的密码(passphrase)。它与-N
的不同之处在于,新密码不在命令中指定,而是执行后再输入。ssh 先要求输入旧密码,然后要求输入两遍新密码。
-R
将指定的主机公钥指纹移出known_hosts
文件
|
|
-t
指定生成密钥的加密算法,一般为dsa
或rsa
|
|
SSH服务器配置
安装基本的依赖
|
|
修改sshd
配置信息
|
|
我们可以修改一下信息:
|
|
给对应用户下增加公钥
生成密钥以后,公钥必须上传到服务器,才能使用公钥登录。
手动设置公钥
OpenSSH 规定,用户公钥保存在服务器的~/.ssh/authorized_keys
文件。你要以哪个用户的身份登录到服务器,密钥就必须保存在该用户主目录的~/.ssh/authorized_keys
文件。只要把公钥添加到这个文件之中,就相当于公钥上传到服务器了。每个公钥占据一行。如果该文件不存在,可以手动创建。
用户可以手动编辑该文件,把公钥粘贴进去,也可以在本机计算机上,执行下面的命令。
|
|
上面示例中,user@host
要替换成你所要登录的用户名和主机名。
注意,authorized_keys
文件的权限要设为644
,即只有文件所有者才能写。如果权限设置不对,SSH 服务器可能会拒绝读取该文件。
自动上传公钥
OpenSSH 自带一个ssh-copy-id
命令,可以自动将公钥拷贝到远程服务器的~/.ssh/authorized_keys
文件。如果~/.ssh/authorized_keys
文件不存在,ssh-copy-id
命令会自动创建该文件。
|
|
上面命令中,-i
参数用来指定公钥文件,user
是所要登录的账户名,host
是服务器地址。如果省略用户名,默认为当前的本机用户名。执行完该命令,公钥就会拷贝到服务器。
默认情况下会与同名的私钥进行校验,如果想不校验的话,那么直接加上-f
重新启动ssh
服务
|
|
常见问题
验证私钥后,仍要求输入密码
在私钥验证通过后,仍然要求输入对应密码的情况下,需要检查以下事项:
- 检查
~/.ssh/authorized_keys
的权限是否为600
,且组权限是否正常 - 检查
~/.ssh
文件夹的权限是否为700
,且组权限是否正常 - 检查
~/.ssh/authorized_keys
是否和私钥匹配,且组权限是否正常
连接服务器时间过长
有可能是因为DNS反查时间太长了,在/etc/ssh/sshd_config
中将useDNS
修改为no
,然后执行如下语句重启ssh服务器。
|
|
如何debug ssh
开启debug模式下的sshd:
|
|
然后在指定连接这个端口下的ssh,无论连接是否成功,一次连接后,在服务器上都会显示对应的日志。