微信号:LinuxHub

介绍:伯乐在线旗下账号,「Linux爱好者」专注分享 Linux/Unix 相关内容,包括:工具资源、使用技巧、课程书籍等.

20 个 OpenSSH 最佳安全实践

2018-03-03 22:47 Linux爱好者

(点击上方公众号,可快速关注)


英文:Vivek Gite,翻译:Linux中国/shipsw

linux.cn/article-9394-1.html


OpenSSH 是 SSH 协议的一个实现。一般通过 scp 或 sftp 用于远程登录、备份、远程文件传输等功能。SSH能够完美保障两个网络或系统间数据传输的保密性和完整性。尽管如此,它最大的优势是使用公匙加密来进行服务器验证。时不时会出现关于 OpenSSH 零日漏洞的传言。本文将描述如何设置你的 Linux 或类 Unix 系统以提高 sshd 的安全性。


OpenSSH 默认设置


  • TCP 端口 – 22

  • OpenSSH 服务配置文件 – sshd_config (位于 /etc/ssh/)


1、 基于公匙的登录


OpenSSH 服务支持各种验证方式。推荐使用公匙加密验证。首先,使用以下 ssh-keygen命令在本地电脑上创建密匙对:


1024 位或低于它的 DSA 和 RSA 加密是很弱的,请不要使用。当考虑 ssh 客户端向后兼容性的时候,请使用 RSA密匙代替 ECDSA 密匙。所有的 ssh 密钥要么使用 ED25519 ,要么使用 RSA,不要使用其它类型。


$ ssh-keygen -t key_type -b bits -C "comment"

 

示例:


$ ssh-keygen -t ed25519 -C "Login to production cluster at xyz corp"

$ ssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa_aws_$(date +%Y-%m-%d) -C "AWS key for abc corp clients"


下一步,使用 ssh-copy-id 命令安装公匙:


$ ssh-copy-id -i /path/to/public-key-file user@host

$ ssh-copy-id user@remote-server-ip-or-dns-name


示例:


$ ssh-copy-id vivek@rhel7-aws-server

 

提示输入用户名和密码的时候,确认基于 ssh 公匙的登录是否工作:


$ ssh vivek@rhel7-aws-server

 



2、 禁用 root 用户登录


禁用 root 用户登录前,确认普通用户可以以 root 身份登录。例如,允许用户 vivek 使用 sudo 命令以 root 身份登录。


在 Debian/Ubuntu 系统中如何将用户 vivek 添加到 sudo 组中


允许 sudo 组中的用户执行任何命令。 将用户 vivek 添加到 sudo 组中


$ sudo adduser vivek sudo

 

使用 id 命令 验证用户组。


$ id vivek

 

在 CentOS/RHEL 系统中如何将用户 vivek 添加到 sudo 组中


在 CentOS/RHEL 和 Fedora 系统中允许 wheel 组中的用户执行所有的命令。使用 usermod 命令将用户 vivek 添加到 wheel 组中:


$ sudo usermod -aG wheel vivek

$ id vivek


测试 sudo 权限并禁用 ssh root 登录


测试并确保用户 vivek 可以以 root 身份登录执行以下命令:


$ sudo -i

$ sudo /etc/init.d/sshd status

$ sudo systemctl status httpd


添加以下内容到 sshd_config 文件中来禁用 root 登录:


PermitRootLogin no

ChallengeResponseAuthentication no

PasswordAuthentication no

UsePAM no


3、 禁用密码登录


所有的密码登录都应该禁用,仅留下公匙登录。添加以下内容到 sshd_config 文件中:


AuthenticationMethods publickey

PubkeyAuthentication yes


CentOS 6.x/RHEL 6.x 系统中老版本的 sshd 用户可以使用以下设置:


PubkeyAuthentication yes

 

4、 限制用户的 ssh 访问


默认状态下,所有的系统用户都可以使用密码或公匙登录。但是有些时候需要为 FTP 或者 email 服务创建 UNIX/Linux 用户。然而,这些用户也可以使用 ssh 登录系统。他们将获得访问系统工具的完整权限,包括编译器和诸如 Perl、Python(可以打开网络端口干很多疯狂的事情)等的脚本语言。通过添加以下内容到 sshd_config 文件中来仅允许用户 root、vivek 和 jerry 通过 SSH 登录系统:


AllowUsers vivek jerry

 

当然,你也可以添加以下内容到 sshd_config 文件中来达到仅拒绝一部分用户通过 SSH 登录系统的效果。


DenyUsers root saroj anjali foo

 

你也可以通过配置 Linux PAM 来禁用或允许用户通过 sshd 登录。也可以允许或禁止一个用户组列表通过 ssh 登录系统。


5、 禁用空密码


你需要明确禁止空密码账户远程登录系统,更新 sshd_config 文件的以下内容:


PermitEmptyPasswords no

 

6、 为 ssh 用户或者密匙使用强密码


为密匙使用强密码和短语的重要性再怎么强调都不过分。暴力破解可以起作用就是因为用户使用了基于字典的密码。你可以强制用户避开字典密码并使用约翰的开膛手工具来检测弱密码。以下是一个随机密码生成器(放到你的 ~/.bashrc 下):


genpasswd() {

    local l=$1

    [ "$l" == "" ] && l=20

    tr -dc A-Za-z0-9_ < /dev/urandom | head -c ${l} | xargs


运行:


genpasswd 16

 

输出:


uw8CnDVMwC6vOKgW

 

7、 为 SSH 的 22端口配置防火墙


你需要更新 iptables/ufw/firewall-cmd 或 pf 防火墙配置来为 ssh 的 TCP 端口 22 配置防火墙。一般来说,OpenSSH 服务应该仅允许本地或者其他的远端地址访问。


Netfilter(Iptables) 配置


更新 /etc/sysconfig/iptables (Redhat 和其派生系统特有文件) 实现仅接受来自于 192.168.1.0/24 和 202.54.1.5/29 的连接,输入:


-A RH-Firewall-1-INPUT -s 192.168.1.0/24 -m state --state NEW -p tcp --dport 22 -j ACCEPT

-A RH-Firewall-1-INPUT -s 202.54.1.5/29 -m state --state NEW -p tcp --dport 22 -j ACCEPT


如果同时使用 IPv6 的话,可以编辑 /etc/sysconfig/ip6tables (Redhat 和其派生系统特有文件),输入:


-A RH-Firewall-1-INPUT -s ipv6network::/ipv6mask -m tcp -p tcp --dport 22 -j ACCEPT

 

将 ipv6network::/ipv6mask 替换为实际的 IPv6 网段。


Debian/Ubuntu Linux 下的 UFW


UFW 是 Uncomplicated FireWall 的首字母缩写,主要用来管理 Linux 防火墙,目的是提供一种用户友好的界面。输入以下命令使得系统仅允许网段 202.54.1.5/29 接入端口 22:


$ sudo ufw allow from 202.54.1.5/29 to any port 22

 

*BSD PF 防火墙配置


如果使用 PF 防火墙 /etc/pf.conf 配置如下:


pass in on $ext_if inet proto tcp from {192.168.1.0/24, 202.54.1.5/29} to $ssh_server_ip port ssh flags S/SA synproxy state

 

8、 修改 SSH 端口和绑定 IP


ssh 默认监听系统中所有可用的网卡。修改并绑定 ssh 端口有助于避免暴力脚本的连接(许多暴力脚本只尝试端口 22)。更新文件 sshd_config 的以下内容来绑定端口 300 到 IP 192.168.1.5 和 202.54.1.5:


Port 300

ListenAddress 192.168.1.5

ListenAddress 202.54.1.5


当需要接受动态广域网地址的连接时,使用主动脚本是个不错的选择,比如 fail2ban 或 denyhosts。


9、 使用 TCP wrappers (可选的)


TCP wrapper 是一个基于主机的访问控制系统,用来过滤来自互联网的网络访问。OpenSSH 支持 TCP wrappers。只需要更新文件 /etc/hosts.allow 中的以下内容就可以使得 SSH 只接受来自于 192.168.1.2 和 172.16.23.12 的连接:


sshd : 192.168.1.2 172.16.23.12

 

10、 阻止 SSH 破解或暴力攻击


暴力破解是一种在单一或者分布式网络中使用大量(用户名和密码的)组合来尝试连接一个加密系统的方法。可以使用以下软件来应对暴力攻击:


  • DenyHosts 是一个基于 Python SSH 安全工具。该工具通过监控授权日志中的非法登录日志并封禁原始 IP 的方式来应对暴力攻击。

    • RHEL / Fedora 和 CentOS Linux 下如何设置 DenyHosts

  • Fail2ban 是另一个类似的用来预防针对 SSH 攻击的工具。

  • sshguard 是一个使用 pf 来预防针对 SSH 和其他服务攻击的工具。

  • security/sshblock 阻止滥用 SSH 尝试登录。

  • IPQ BDB filter 可以看做是 fail2ban 的一个简化版。


11、 限制 TCP 端口 22 的传入速率(可选的)


netfilter 和 pf 都提供速率限制选项可以对端口 22 的传入速率进行简单的限制。


Iptables 示例


以下脚本将会阻止 60 秒内尝试登录 5 次以上的客户端的连入。


#!/bin/bash

inet_if=eth1

ssh_port=22

$IPT -I INPUT -p tcp --dport ${ssh_port} -i ${inet_if} -m state --state NEW -m recent --set

$IPT -I INPUT -p tcp --dport ${ssh_port} -i ${inet_if} -m state --state NEW -m recent --update --seconds 60 --hitcount 5


在你的 iptables 脚本中调用以上脚本。其他配置选项:


$IPT -A INPUT -i ${inet_if} -p tcp --dport ${ssh_port} -m state --state NEW -m limit --limit 3/min --limit-burst 3 -j ACCEPT

$IPT -A INPUT -i ${inet_if} -p tcp --dport ${ssh_port} -m state --state ESTABLISHED -j ACCEPT

$IPT -A OUTPUT -o ${inet_if} -p tcp --sport ${ssh_port} -m state --state ESTABLISHED -j ACCEPT

# another one line example

# $IPT -A INPUT -i ${inet_if} -m state --state NEW,ESTABLISHED,RELATED -p tcp --dport 22 -m limit --limit 5/minute --limit-burst 5-j ACCEPT


其他细节参见 iptables 用户手册。


*BSD PF 示例


以下脚本将限制每个客户端的连入数量为 20,并且 5 秒内的连接不超过 15 个。如果客户端触发此规则,则将其加入 abusive_ips 表并限制该客户端连入。最后 flush 关键词杀死所有触发规则的客户端的连接。


sshd_server_ip = "202.54.1.5"

table <abusive_ips> persist

block in quick from <abusive_ips>

pass in on $ext_if proto tcp to $sshd_server_ip port ssh flags S/SA keep state (max-src-conn 20, max-src-conn-rate 15/5, overload <abusive_ips> flush)


12、 使用端口敲门(可选的)


端口敲门是通过在一组预先指定的封闭端口上生成连接尝试,以便从外部打开防火墙上的端口的方法。一旦指定的端口连接顺序被触发,防火墙规则就被动态修改以允许发送连接的主机连入指定的端口。以下是一个使用 iptables 实现的端口敲门的示例:


$IPT -N stage1

$IPT -A stage1 -m recent --remove --name knock

$IPT -A stage1 -p tcp --dport 3456 -m recent --set --name knock2

 

$IPT -N stage2

$IPT -A stage2 -m recent --remove --name knock2

$IPT -A stage2 -p tcp --dport 2345 -m recent --set --name heaven

 

$IPT -N door

$IPT -A door -m recent --rcheck --seconds 5 --name knock2 -j stage2

$IPT -A door -m recent --rcheck --seconds 5 --name knock -j stage1

$IPT -A door -p tcp --dport 1234 -m recent --set --name knock

 

$IPT -A INPUT -m --state ESTABLISHED,RELATED -j ACCEPT

$IPT -A INPUT -p tcp --dport 22 -m recent --rcheck --seconds 5 --name heaven -j ACCEPT

$IPT -A INPUT -p tcp --syn -j door


13、 配置空闲超时注销时长


用户可以通过 ssh 连入服务器,可以配置一个超时时间间隔来避免无人值守的 ssh 会话。 打开 sshd_config 并确保配置以下值:


ClientAliveInterval 300

ClientAliveCountMax 0


以秒为单位设置一个空闲超时时间(300秒 = 5分钟)。一旦空闲时间超过这个值,空闲用户就会被踢出会话。更多细节参见如何自动注销空闲超时的 BASH / TCSH / SSH 用户。


14、 为 ssh 用户启用警示标语


更新 sshd_config 文件如下行来设置用户的警示标语:


Banner /etc/issue

 

`/etc/issue 示例文件:



以上是一个标准的示例,更多的用户协议和法律细节请咨询你的律师团队。


15、 禁用 .rhosts 文件(需核实)


禁止读取用户的 ~/.rhosts 和 ~/.shosts 文件。更新 sshd_config 文件中的以下内容:


IgnoreRhosts yes

 

SSH 可以模拟过时的 rsh 命令,所以应该禁用不安全的 RSH 连接。


16、 禁用基于主机的授权(需核实)


禁用基于主机的授权,更新 sshd_config 文件的以下选项:


HostbasedAuthentication no

 

17、 为 OpenSSH 和操作系统打补丁


推荐你使用类似 yum、apt-get 和 freebsd-update 等工具保持系统安装了最新的安全补丁。


18、 Chroot OpenSSH (将用户锁定在主目录)


默认设置下用户可以浏览诸如 /etc、/bin 等目录。可以使用 chroot 或者其他专有工具如 rssh 来保护 ssh 连接。从版本 4.8p1 或 4.9p1 起,OpenSSH 不再需要依赖诸如 rssh 或复杂的 chroot(1) 等第三方工具来将用户锁定在主目录中。可以使用新的 ChrootDirectory 指令将用户锁定在其主目录,参见这篇博文。


19. 禁用客户端的 OpenSSH 服务


工作站和笔记本不需要 OpenSSH 服务。如果不需要提供 ssh 远程登录和文件传输功能的话,可以禁用 sshd 服务。CentOS / RHEL 用户可以使用 yum 命令 禁用或删除 openssh-server:


$ sudo yum erase openssh-server

 

Debian / Ubuntu 用户可以使用 apt 命令/apt-get 命令 删除 openssh-server:


$ sudo apt-get remove openssh-server

 

有可能需要更新 iptables 脚本来移除 ssh 的例外规则。CentOS / RHEL / Fedora 系统可以编辑文件 /etc/sysconfig/iptables 和 /etc/sysconfig/ip6tables。最后重启 iptables 服务:


# service iptables restart

# service ip6tables restart


20. 来自 Mozilla 的额外提示


如果使用 6.7+ 版本的 OpenSSH,可以尝试下以下设置:



使用以下命令获取 OpenSSH 支持的加密方法:


$ ssh -Q cipher

$ ssh -Q cipher-auth

$ ssh -Q mac

$ ssh -Q kex

$ ssh -Q key



如何测试 sshd_config 文件并重启/重新加载 SSH 服务?


在重启 sshd 前检查配置文件的有效性和密匙的完整性,运行:


$ sudo sshd -t

 

扩展测试模式:


$ sudo sshd -T

 

最后,根据系统的的版本重启 Linux 或类 Unix 系统中的 sshd 服务:


$ [sudo systemctl start ssh][38] ## Debian/Ubunt Linux##

$ [sudo systemctl restart sshd.service][39] ## CentOS/RHEL/Fedora Linux##

$ doas /etc/rc.d/sshd restart ## OpenBSD##

$ sudo service sshd restart ## FreeBSD##


其他建议


  1. 使用 2FA 加强 SSH 的安全性 – 可以使用 OATH Toolkit 或 DuoSecurity 启用多重身份验证。

  2. 基于密匙链的身份验证 – 密匙链是一个 bash 脚本,可以使得基于密匙的验证非常的灵活方便。相对于无密码密匙,它提供更好的安全性。


关于作者


作者是 nixCraft 的创始人,一个经验丰富的系统管理员和 Linux/Unix 脚本培训师。他曾与全球客户合作,领域涉及 IT,教育,国防和空间研究以及非营利部门等多个行业。请在 TwitterFacebookGoogle+ 上关注他。



看完本文有收获?请分享给更多人

关注「Linux 爱好者」,提升Linux技能

淘口令复制以下红色内容,再打开手淘即可购买

范品社,使用¥极客T恤¥抢先预览(长按复制整段文案,打开手机淘宝即可进入活动内容)

近期,北京地区正常发货,但派件时间有所延长

 
Linux爱好者 更多文章 2017 年 Google 开源了这些超赞的项目:12 篇热文回顾 如何在 Linux\/Unix 中不重启 Vim 而重新加载 .vimrc&n 什么是 LLVM?Swift, Rust, Clang 等语言背后的支持 2017 年度最佳 Linux 桌面发行版出炉:Ubuntu 夺冠 每个系统管理员都要知道的 30 个 Linux 系统监控工具
猜您喜欢 对待棘手bug,新手与大牛的差距在哪里? Android 安全测试初探(三) 企业安全:为何总有修不完的漏洞? H5游戏引擎LayaBox融资成功,A轮进帐1亿! 编程的精进之法|洞见