SSH

SSH

概念与原理

SSH是一种协议标准,其目的是实现安全远程登录以及其它安全网络服务。SSH的具体的实现有很多,既有开源实现的OpenSSH,也有商业实现方案。使用范围最广泛的当然是开源实现OpenSSH。 SSH通话过程:

  1. Client将自己的公钥存放在Server上,追加在文件authorized_keys中。
  2. Server端接收到Client的连接请求后,会在authorized_keys中匹配到Client的公钥pubKey,并生成随机数R,用Client的公钥对该随机数进行加密得到pubKey(R),然后将加密后信息发送给Client。
  3. Client端通过私钥进行解密得到随机数R,然后对随机数R和本次会话的SessionKey利用MD5生成摘要Digest1,发送给Server端。
  4. Server端会也会对R和SessionKey利用同样摘要算法生成Digest2。
  5. Server端会最后比较Digest1和Digest2是否相同,完成认证过程。

这个过程本身是安全的,但是实施的时候存在一个风险:如果有人截获了登录请求,然后冒充远程主机,将伪造的公钥发给用户,那么用户很难辨别真伪。因为不像https协议,SSH协议的公钥是没有证书中心(CA)公证的,也就是说,都是自己签发的。可以设想,如果攻击者插在用户与远程主机之间(比如在公共的wifi区域),用伪造的公钥,获取用户的登录密码。再用这个密码登录远程主机,那么SSH的安全机制就荡然无存了。这种风险就是著名的”中间人攻击”(Man-in-the-middle attack)。

.ssh 文件夹中存在四个文件:

  1. id_rsa:保存私钥
  2. id_rsa.pub:保存公钥
  3. authorized_keys:保存已授权的客户端公钥
  4. known_hosts:保存已认证的远程主机ID 一台主机可能既是Client,也是Server。所以会同时拥有authorized_keys和known_hosts。

/etc/ssh/ssh_config 客户端的配置文件

/etc/ssh/sshd_config 服务端的配置文件。

命令

SSH分客户端openssh-client和openssh-server。如果你只是想登陆别的机器的SSH只需要安装openssh-client(ubuntu有默认安装,如果没有则sudoapt-get install openssh-client),如果要使本机开放SSH服务就需要安装openssh-server。Ubuntu缺省已经安装了ssh client。

登录操作

1
2
3
4
5
6
7
8
# 以用户名user,登录远程主机host
$ ssh user@host

# 本地用户和远程用户相同,则用户名可省去
$ ssh host

# SSH默认端口22,可以用参数p修改端口
$ ssh -p 2017 user@host

管理操作

1
2
3
4
5
6
7
8
9
$ sudo systemctl start ssh

$ sudo systemctl restart ssh

$ sudo systemctl stop ssh

$ sudo systemctl status ssh

$ sshd -T

本地端口转发

举例:

$ ssh -L 5069:127.0.0.1:5069 sunchuanxi@123.25.145.146

有时,绑定本地端口还不够,还必须指定数据传送的目标主机,从而形成点对点的”端口转发”。为了区别后文的”远程端口转发”,我们把这种情况称为”本地端口转发”(Local forwarding)。假定host1是本地主机,host2是远程主机。由于种种原因,这两台主机之间无法连通。但是,另外还有一台host3,可以同时连通前面两台主机。因此,很自然的想法就是,通过host3,将host1连上host2。我们在host1执行下面的命令:

$ ssh -L 2121:host2:21 host3

命令中的L参数一共接受三个值,分别是”本地端口:目标主机:目标主机端口”,它们之间用冒号分隔。这条命令的意思,就是指定SSH绑定本地端口2121,然后指定host3将所有的数据,转发到目标主机host2的21端口(假定host2运行FTP,默认端口为21)。

这样一来,我们只要连接host1的2121端口,就等于连上了host2的21端口。

$ ftp localhost:2121

“本地端口转发”使得host1和host3之间仿佛形成一个数据传输的秘密隧道,因此又被称为”SSH隧道”。

下面是一个比较有趣的例子。

$ ssh -L 5900:localhost:5900 host3

它表示将本机的5900端口绑定host3的5900端口(这里的localhost指的是host3,因为目标主机是相对host3而言的)。

另一个例子是通过host3的端口转发,ssh登录host2。

$ ssh -L 9001:host2:22 host3

这时,只要ssh登录本机的9001端口,就相当于登录host2了。

$ ssh -p 9001 localhost

上面的-p参数表示指定登录端口。

查看连接数

$ netstat -nat grep -i ‘22’ wc -l

配置

  • ClientAliveCountMax

    Sets the number of client alive messages (see below) which may be sent without sshd(8) receiving any messages back from the client. If this threshold is reached while client alive messages are being sent, sshd will disconnect the client, terminating the session. It is important to note that the use of client alive messages is very different from TCPKeepAlive (below). The client alive messages are sent through the encrypted channel and therefore will not be spoofable. The TCP keepalive option enabled by TCPKeepAlive is spoofable. The client alive mechanism is valuable when the client or server depend on knowing when a connection has become inactive.

    The default value is 3. If ClientAliveInterval (see below) is set to 15, and ClientAliveCountMax is left at the default, unresponsive SSH clients will be disconnected after approximately 45 sec‐ onds.

  • ClientAliveInterval

    Sets a timeout interval in seconds after which if no data has been received fromthe client, sshd(8) will send a message through the encryptedchannel to request aresponse from the client. The default is 0, indicating that these messages will not be sent to the client.

  • MaxSessions

    Specifies the maximum number of open shell, login or subsystem (e.g. sftp) sessions permitted per network connection. Multiple sessions may be established by clients that support connection multi‐ plexing. Setting MaxSessions to 1 will effectively disable session multiplexing, whereas setting it to 0 will prevent all shell, login and subsystem sessions while still permitting forwarding. The default is 10.

  • MaxStartups

    Specifies the maximum number of concurrent unauthenticated connections to the SSH daemon. Additional connections will be dropped until authentication succeeds or the LoginGraceTime expires for a connection. The default is 10:30:100.

    Alternatively, random early drop can be enabled by specifying the three colon separated values “start:rate:full” (e.g. “10:30:60”). sshd(8) will refuse connection attempts with a probability of “rate/100” (30%) if there are currently “start” (10) unauthenticated connections. The probability increases linearly and all connection attempts are refused if the number of unauthenticated con‐ nections reaches “full” (60).

如果要限制用户登录数量的话,就需要在/etc/security/limits.conf中添加

1
userid  - maxlogins  1

linux limits.conf 配置 limits.conf 文件实际是 Linux PAM(插入式认证模块,Pluggable Authentication Modules)中 pam_limits.so 的配置文件,而且只针对于单个会话。

limits.conf的格式如下:

username @groupname type resource limit
username @groupname:设置需要被限制的用户名,组名前面加@和用户名区别。也可以用通配符*来做所有用户的限制。

疑问与解答

  1. known_hosts中存储的内容是什么? known_hosts中存储是已认证的远程主机host key,每个SSH Server都有一个secret, unique ID, called a host key。

  2. host key何时加入known_hosts的? 当我们第一次通过SSH登录远程主机的时候,Client端会有如下提示:

    1
    2
    Host key not found from the list of known hosts.
    Are you sure you want to continue connecting (yes/no)?
    

此时,如果我们选择yes,那么该host key就会被加入到Client的known_hosts中,格式如下:

1
2
# domain name+encryption algorithm+host key
example.hostname.com ssh-rsa AAAAB4NzaC1yc2EAAAABIwAAAQEA。。。
  1. 为什么需要known_hosts? 最后探讨下为什么需要known_hosts,这个文件主要是通过Client和Server的双向认证,从而避免中间人(man-in-the-middle attack)攻击,每次Client向Server发起连接的时候,不仅仅Server要验证Client的合法性,Client同样也需要验证Server的身份,SSH client就是通过known_hosts中的host key来验证Server的身份的。

  2. Linux关闭ssh(关闭终端等)后运行的程序或者服务自动停止,如python3 a.py &。

解决:使用nohup命令让程序在关闭窗口(切换SSH连接)的时候程序还能继续在后台运行,nohup python3 a.py &

参考

SSH原理与运用(二):远程操作与端口转发