ssh 实用技巧与优化

2018-08-26 22:28:27   最后更新: 2018-08-26 22:28:27   访问数量:76




ssh 工具对于服务端开发人员来说是再熟悉不过了,他是“安全外壳协议”(Secure Shell)的缩写,由 IETF 的网络小组(Network Working Group)所制定

ssh 是目前比较可靠的建立在应用层基础上的安全协议,专为远程登录会话和其他网络服务提供安全性的协议

利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题,几乎所有 UNIX 平台以及其他平台都可以运行 ssh

本文我们来介绍一下 ssh 的一些常用技巧

 

通常我们使用 OpenSSH 的客户端来实现服务器的远程控制

OpenSSH 是 SSH (Secure SHell) 协议的免费开源实现,他是使用SSH透过计算机网络加密通讯的实现,他的图标是经典的河豚标志

 

 

点击下面的链接即可获取安装包安装 OpenSSH:

OpenSSH Portable Release

 

SSH 采用的是“非对称密钥系统”,即耳熟能详的公钥私钥加密系统,其安全验证又分为两种级别:

  1. 基于口令的安全验证
  2. 基于密钥的安全验证

 

基于口令的安全验证

基于口令的安全验证是一种最为常见的验证方式,其验证过程如下:

  1. 客户端发起连接请求
  2. 远程主机收到客户端登录请求后,把自己的公钥发给客户端
  3. 客户端收到远程主机的公钥后,使用远程主机的公钥加密登录密码,并将加密后的登录密码与自己的公钥一起发送给远程主机
  4. 远程主机接收到客户端的公钥及加密后的登录密码,用自己的私钥解密收到的登录密码,验证密码
  5. 客户端与远程主机都已经拥有了对方的公钥,此时就可以开始双向加密的传输了

 

那么,这个传输过程是安全的吗?显然,客户端与远程主机都没有暴露自己的私钥,从而保证了单向加密与专属解密

但是如果存在一个远程服务器B,他拦截了客户端到远程主机的请求,他先是获取到真正的远程主机的公钥,然后将自己的公钥发送给客户端,客户端加密登录密码后发送给远程服务器B,远程服务器B就可以用自己的私钥获取到客户端的密码了,从而实现对远程服务器的侵入

为了防止上述的情况发生,客户端在首次发起连接请求时,会主动提示用户当前远程主机的“公钥指纹”,如果这次连接被拦截,则公钥指纹就会是远程服务器B的,从而让用户觉察到这一问题

如果用户确认没有问题,就可以输入密码进行登录了,当远程的主机接受以后,该台服务器的公钥就会保存到 ~/.ssh/known_hosts文件中,此后同一公钥就不会再次提示了

 

基于密匙的安全验证

这种方式是将客户端公钥放在远程服务器上,当客户端要连接到服务器上时,客户端就会向服务器请求使用密匙进行安全验证

远程服务器收到客户端的请求后,会在该服务器上用户 home 目录下查询公钥,然后与发送过来的公钥比较,如果一致则用该公钥加密“质询”请求,客户端收到质询请求后,用私钥解密,回传给远程服务器,远程服务器验证质询后连接就这样建立了

基于密匙的安全验证省去了客户端口令,从而可以实现免密登录

 

配置方式

  1. 客户端通过 ssh-keygen -t rsa 命令生成 RSA 密钥
  2. 将客户端当前用户 home 目录下的 .ssh/id_rsa.pub 文件中的内容拷贝并追加到远程服务器目标用户 home 目录下 .ssh/authorized_keys 文件尾部
  3. 配置远程服务器支持基于密钥验证 -- 在 /etc/ssh/sshd_config 文件中配置 PubkeyAuthentication yes

 

如果遇到权限问题,则执行:

chmod 700 .ssh chmod 600 .ssh/authorized_keys

 

 

SFTP 是指 SSH 文件传输协议(SSH File Transfer protocol),它提供了可信数据流下的文件访问、文件传输以及文件管理功能

一旦客户端拥有了 SSH 远程访问的权限,就默认开通了 SFTP 连接的权限,无需再次开通

但是,在某些场景下,系统管理员想要允许极少数用户在可以传输文件到Linux机器中,但是不允许使用 SSH,要实现这一目的,我们就可以使用SFTP,通过为其构建chroot环境就可以实现了

 

操作步骤

  • 创建组

执行下面的命令为这类用户创建一个附属的组:

groupadd sftp_users

 

 

  • 分配附属组给用户

如果用户在系统上不存在,那么就是用下面的命令创建用户并分配附属组:

useradd -G sftp_users -s /sbin/nologin jack passwd jack

 

 

如果用户已经存在,那么执行下面的命令更改用户所在的组:

usermod –G sftp_users -s /sbin/nologin jack

 

 

  • 修改配置文件

在 /etc/ssh/ssh_config 配置文件中追加下面的行:

Match Group sftp_users # 以下的行仅仅匹配 sftp_users 组中的用户 X11Forwarding no # 关闭 GUI AllowTcpForwarding no # 不允许通过 tcp 端口转发,保护其他 tcp 连接 ChrootDirectory %h # 设置验证后用户根目录为家目录,保证安全性 ForceCommand internal-sftp # 强制执行内部 sftp,并忽略任何~/.ssh/rc文件中的命令

 

 

  • 设置权限并重启 ssh 服务

首先,我们为 jack 的 home 目录分配权限:

chmod 755 /home/jack chown root /home/jack chgrp -R sftp_users /home/jack

 

 

执行下面命令重启 ssh 服务,从而让配置生效:

service sshd restart

 

 

这样 jack 用户不能够通过 ssh 协议登录到远程服务器上

 

但他可以通过 sftp 上传和下载文件,但他仍然不能访问 home 目录上层的文件,因为 home 目录是该用户的根目录

 

ssh 或 sftp 连接远程服务器的时候,如果长时间不操作客户端,常常会自动断开或无响应

有两种方法可以解决这个问题,分别是更改客户端配置与更改服务端配置

 

更改客户端配置自动发送心跳

虽然 putty、SecureCRT、XShell 等客户端都有自动发送心跳的机制来避免自动断开的问题,但是这并不是从根源上解决问题,并不保险

我们在客户端的 /etc/ssh/ssh_config 配置文件中追加下面两行配置:

ServerAliveInterval 20 # 每隔 20 秒向服务器发送一次心跳 ServerAliveCountMax 999 # 若超过 999 次请求都没有发送成功,则主动断开与服务器的连接

 

 

这样,客户端会在空闲时始终向服务端发送心跳,从而避免服务端超时断开连接,而适当的主动断开阈值又避免了本地主动断开

 

更改服务端配置自动发送心跳

如果服务端定时向所有客户端都发送心跳,那么,就能够实时监测所有客户端连接的存活状况了,这通过以下配置也是可以实现的

在 /etc/ssh/ssh_config 文件中追加下面两行配置:

ClientAliveInterval 30 # 每间隔 30 秒向客户端发送一次心跳请求 ClientAliveCountMax 6 # 6 次心跳无响应则断开连接

 

 

这样在持续 30 * 6 = 180 秒客户端无响应后,服务器会主动断开该连接

 

有时你会发现通过 ssh 连接远程服务器登录很慢,这通常是因为 DNS 反向解析引起的

众所周知,DNS 的正向解析即通过域名到 IP 的映射让查询者知道域名具体对应的 IP 地址,但是有时为了防止域名伪造,需要通过 IP 去反向查询域名,来确定远程服务器的 IP 是否对应的就是所使用的域名,这就造成了访问时间的消耗

当然,客户端与 DNS 服务器的通信耗时也是不可忽视的,这就是为什么我们在 ssh 命令中将远程服务器的域名改为 ip,就会快很多,因此我们从这两方面来考虑优化

 

关闭域名反向解析

在远程服务器上的 /etc/ssh/sshd_config 文件尾部追加下面的配置来关闭域名反向解析:

UseDNS no

 

虽然配置文件中[UseDNS yes]被注释掉了,但该开关默认是开启的

 

配置优先通过 host 文件解析域名、ip 映射

  1. 首先你需要在远程服务器上的 /etc/hosts 文件中添加客户端的 ip 和 hostname
  2. 将 /etc/nsswitch.conf 文件中的配置修改为 hosts: files,这样远程服务器就不再通过 DNS 解析域名与 IP 了
  3. 执行 service ssh restart 重启 ssh 服务使配置生效

 

从此远程服务器不再使用 DNS,需要注意的是,这样的配置是存在一定的风险的

 






技术帖      技术分享      server      client      ssh      rsa      sftp      openssh     


京ICP备15018585号