高效安全的使用SSH

2017-08-20|Categories: External cmd, Linux, macOS|

ssh是Linux的标配工具,也是系统管理员每天必须使用的工具,通过一些简单的配置提升ssh使用效率,可以给日常工作带来明显的便利。以下就针对macOS和Linux默认的OpenSSH工具做必要的配置,以便安全高效的使用。

简化ssh登录流程

  • 默认的ssh登录方式是:ssh user@host
  • 如果本机用户名和远程主机用户名相同,可以省略用户名:ssh host
  • 如果远程主机ssh端口不是默认的22,登录时需要指定端口:ssh -p 12345 user@host

假设我要登录的主机没有域名,只有IP地址123.45.67.89,ssh端口是自定的12345,登录用户是user1,那我的登录命令就是:ssh -p 12345 user1@123.45.67.89,这样的命令冗长、容易输错,通过下面的配置,可以避免每次登陆都输入这种冗长的命令。

vim ~/.ssh/config

Host host_name
    HostName 123.45.67.89
    Port 12345
    User login_name

在上面的配置中,

  • 缩进不是必须的,只是为了有多组配置时便于阅读。
  • host_name可以随便起一个名字,使用字母和数字,便于自己记忆即可。
  • login_name必须是远程主机上允许登录的用户名。

假设host_nameh1,这时的登录命令就是:ssh user1@h1,相比之前的ssh -p 12345 user1@123.45.67.89,击键次数少了一大半。

还可以通过设置alias进一步缩短登录命令:alias h1='ssh user1@h1',然后只要输入h1回车就可以登录。

使用公钥自动登录

通过前面的方式登录时,每次都需要输入密码,非常麻烦。是否可以把这一步也「简化」?答案是肯定的,使用公钥登录即可。

所谓"公钥登录",原理很简单,就是用户将自己的公钥储存在远程主机上。登录的时候,远程主机会向用户发送一段随机字符串,用户用自己的私钥加密后,再发回来。远程主机用事先储存的公钥进行解密,如果成功,就证明用户是可信的,直接允许登录shell,不再要求密码。

这种方法要求用户必须提供自己的公钥。如果没有现成的,可以直接用ssh-keygen生成一个:

ssh-keygen

运行上面的命令以后,系统会出现一系列提示,可以一路回车。其中有一个问题是,要不要对私钥设置口令(passphrase),如果担心私钥的安全,这里可以设置一个。

运行结束以后,在$HOME/.ssh/目录下,会生成两个文件id_rsa.pubid_rsa,前者是你的公钥,后者是你的私钥。

这时再输入下面的命令,将公钥传送到远程主机host上面:

ssh-copy-id user@host

好了,从此你再登录,就不需要输入密码了。如果还是不行,就打开远程主机的/etc/ssh/sshd_config这个文件,确认下面几行前面的#已经删除掉。

RSAAuthentication       yes
PubkeyAuthentication    yes
AuthorizedKeysFile      .ssh/authorized_keys

然后,重启远程主机的ssh服务。

# CentOS 6
service sshd restart

# CentOS 7
systemctl restart sshd

保持ssh会话不中断

我买了搬瓦工的VPS之后,刚开始用ssh远程连接时会频繁掉线,而ssh掉线之后会尝试重新连接,在此期间终端会失去响应,让人不胜其烦,几番搜索之后,最终从Stack Overflow找到了解决此问题的方案:

配置ssh客户端

如果希望新的配置对所有用户生效,就修改/etc/ssh/ssh_config,如果只想对当前用户生效,就编辑~/.ssh/config

vim ~/.ssh/config

# 星号表示下面的设置对ssh连接的所有主机都有效
Host *
    ServerAliveInterval 100
  • ServerAliveInterval 100:设置超时间隔为100秒,在此之后如果仍没有从服务器接收到数据,客户端将向服务器发送活动消息(一个空数据包(NULL packet))来请求来自服务器的响应,以保持连接处于活动状态。默认值为0,表示不会发送活动消息到服务器。

配置ssh服务器(sshd)

vim /etc/ssh/sshd_config

# TCPKeepAlive      yes
ClientAliveInterval 60
ClientAliveCountMax 10000
  • TCPKeepAlive yes:确保某些防火墙不会丢弃空闲连接。

    Specifies whether the system should send TCP keepalive messages to the other side. If they are sent, death of the connection or crash of one of the machines will be properly noticed. However, this means that connections will die if the route is down temporarily, and some people find it annoying. On the other hand, if TCP keepalives are not sent, sessions may hang indefinitely on the server, leaving "ghost" users and consuming server resources.

    The default is yes (to send TCP keepalive messages), and the server will notice if the network goes down or the client host crashes. This avoids infinitely hanging sessions.

  • ClientAliveInterval 60:服务器将等待60秒,然后将活动消息发送到客户端以保持连接处于活动状态。

  • ClientAliveCountMax 10000:服务器将向客户端发送活动消息,即使它没有收到客户端返回的任何消息。最大次数10000次,达到此阈值,sshd将断开客户端,终止会话。

    注意,使用客户端活动消息与TCPKeepAlive非常不同。客户端活动消息通过加密通道发送,因此不会被欺骗,而TCPKeepAlive启用的TCP keepalive选项是可伪造的。

    默认值为3,如果ClientAliveInterval设置为15,并且ClientAliveCountMax保留为默认值,则大约45秒后,无响应的SSH客户端将断开连接。

重启ssh服务器

# CentOS 6
service sshd restart

# CentOS 7
systemctl restart sshd

正确关闭失去响应的ssh会话

假设ssh连接的两端(服务器、客户端)配置不正确,或者远程主机宕机,又或者网络连接中断,ssh连接远程主机的终端都会失去响应(frozen),按任何键都无法显示到终端上,此时可以按照如下顺序迅速按键,正确断开ssh会话:

<ENTER>     # 回车键
~           # 波浪号
.           # 圆点(句点)

这会发送一个转义序列到本地ssh客户端,使它中断连接,所以即使没有互联网连接也可以生效。

ssh的转义序列可以在man ssh搜索关键字ESCAPE CHARACTERS找到,但是,输入转义序列之前,必须敲回车键换行,否则转义序列无法被识别。

~.      Disconnect.

~^Z     Background ssh.

~#      List forwarded connections.

~&      Background ssh at logout when waiting for forwarded connection /
        X11 sessions to terminate.

~?      Display a list of escape characters.

~B      Send a BREAK to the remote system (only useful if the peer sup-
        ports it).

~C      Open command line.  Currently this allows the addition of port
        forwardings using the -L, -R and -D options (see above).  It also
        allows the cancellation of existing port-forwardings with
        -KL[bind_address:]port for local, -KR[bind_address:]port for
        remote and -KD[bind_address:]port for dynamic port-forwardings.
        !command allows the user to execute a local command if the
        PermitLocalCommand option is enabled in ssh_config(5).  Basic
        help is available, using the -h option.

~R      Request rekeying of the connection (only useful if the peer sup-
        ports it).

~V      Decrease the verbosity (LogLevel) when errors are being written
        to stderr.

~v      Increase the verbosity (LogLevel) when errors are being written
        to stderr.

配置sftp

如果要让服务器上的某个目录可以通过sftp访问,需要在/etc/ssh/sshd_config里设置:

# 启用sftp子系统
Subsystem   sftp    internal-sftp

# 声明以下设置仅对 sftp01 这个用户有效,
# 也就是授权 sftp01 这个用户通过sftp访问下面 `ChrootDirectory` 定义的路径。
# 也可以通过 `Match Group group_name` 给 用户组 授权。
Match       User    sftp01

# `ChrootDirectory`后面的路径中只能包含目录,每一个目录的所有者都必须是root,
# 如果有一个不是,就会报错。
ChrootDirectory     /apps/nginx/html
ForceCommand        internal-sftp

# 如果后续还有其它选项,但不是针对 sftp01 这一个用户,而是影响所有用户,
# 必须重新声明 `Match all` 来终止 `Match User sftp01` 的作用域。

Leave A Comment