Debian10_Centos8_fail2ban_sshd加密算法_限制连接数
转载注明来源: 本文链接 来自osnosn的博客,写于 2020-11-7.
- Debian-10 的 fail2ban 支持 ipv6。防火墙内核是 nft,缺省用 iptables/ip6tables 指令,也可以装 nftables 用 nft 指令。
- CentOS-8 的 fail2ban 支持 IPv6. 防火墙内核用 nft,缺省用 firewall-cmd, nft, iptables/ip6tables 指令。
- CentOS-7 的 fail2ban 还不支持 IPv6. 防火墙内核是 iptables,缺省用 firewall-cmd, iptables 指令。
- 如果系统禁止所有用户的密码登录,安装 fail2ban 就非必须了。不过还是有不少扫描的,log会很大,很讨厌,还是装上好。
安装配置 fail2ban (debian10)
apt install fail2ban
- debian-10 安装后,默认就已经"激活" 并 "启动"
- 创建 /etc/fail2ban/filter.d/nginx-MyRule.local (按需。如果你不需要,就不用创建)
这是自定义的nginx访问的规则。
目的是阻止网页的扫描,如果有大量访问"文件不存在的页面",就禁了他。[INCLUDES] #before = botsearch-common.conf [Init] # Block is the actual non-found directories to block block = \/?(<webmail>|<phpmyadmin>|<wordpress>|cgi-bin|mysqladmin)[^,]* # These are just convenient definitions that assist the blocking of stuff that # isn't installed webmail = roundcube|(ext)?mail|horde|(v-?)?webmail phpmyadmin = (typo3/|xampp/|admin/|)(pma|(php)?[Mm]y[Aa]dmin) wordpress = wp-(login|signup|admin)\.php [Definition] failregex = ^<HOST> \- \S+ \[\] \"(GET|POST|HEAD) \/\S+ \S+\" (400|401|404) .+$ ^<HOST> \- \S+ \[\] \"(GET|POST|HEAD) \/<block> \S+\" 404 .+$ ignoreregex = datepattern = {^LN-BEG}%%ExY(?P<_sep>[-/.])%%m(?P=_sep)%%d[T ]%%H:%%M:%%S(?:[.,]%%f)?(?:\s*%%z)? ^[^\[]*\[({DATE}) {^LN-BEG} # Author: MyLocalRule
- 创建 /etc/fail2ban/jail.local
[sshd] enabled = true port = 22,2222 #ignoreip=127.0.0.1/8 192.168.0.0/16 ignoreip=127.0.0.1/8 findtime=600 # 一次ssh密码错产生3条匹配 maxretry=10 bantime=3600 # 以下部分,按需。(不需要就整段不要) [nginx-MyRule] enabled = true port = http,https,10443 logpath = %(nginx_access_log)s ignoreip = 127.0.0.1/8 maxretry = 30 findtime = 1200 bantime = 14400
- 重启
service fail2ban reload
- fail2ban 启动后不会马上在iptables中创建规则。所以这时去看防火墙规则,是没有变化的。要等到需要deny时,才动态创建的。
- 如果满足ban规则,因为 debian-10 默认是用 iptables/ip6tables 指令。
- 默认用 multiport 动作。一条对应多个端口的规则分别加入iptables/ip6tables的
INPUT
,跳转到f2b-sshd。 - ipv4, debian-10 会在 iptables 的
Chain f2b-sshd
中插入对应ipv4的deny规则。 - ipv6, debian-10 会在 ip6tables 的
Chain f2b-sshd
中插入对应ipv6的deny规则。 - 以上规则,最终会自动转换为 nft rule 执行。
- 多端口的一条规则分别加入
table ip(6) filter { chain INPUT { ... } }
跳转f2b-sshd。 - ipv4/ipv6的deny插入
table ip(6) filter { chain f2b-sshd { ... } }
。
- 多端口的一条规则分别加入
- 默认用 multiport 动作。一条对应多个端口的规则分别加入iptables/ip6tables的
安装配置 fail2ban (centos-8)
dnf install fail2ban
- 其他配置,和 debian-10 相同。
- centos-8 安装后,没有"激活" 和 "启动", 所以需要手工激活/启动。
systemctl enable fail2ban; systemctl start fail2ban
- fail2ban 启动后不会在nft中创建规则。所以nft中看不到变化。要等到需要deny时,才会在nft中添加rule。
- 如果满足ban规则,因为 centos-8 默认是用 nft 做防火墙。
- 用 tcp dport 动作。一个端口插入一条deny规则。
- ipv4/ipv6, centos-8 都会在
table inet firewalld { chain filter_IN_public_deny { ... } }
插入deny规则。 - iptables/ip6tables 中 没有规则。
更换 sshd 的端口
- 把 sshd 的端口从 22 改为一个不常用的端口。能大幅度减少被猜密码的频率。
为了安全,建议禁止root通过密码登录
- 登录服务器:
- 用 ssh 的 key(密钥) 登录 root。
- 用密码,登录一个普通用户,再 su 到 root。
- 从特定的 IP,用密码,登录 root。
- 见【配置sshd_除了特定ip外_仅密钥登录】
安装配置 fail2ban (debian11(bullseye))
- 2023-03 重新安装 fail2ban的记录,改用 nftables。
apt install fail2ban
- debian-11 安装后,默认就已经"激活" 并 "启动"
默认,针对端口 22,使用 "iptables-multiport","REJECT"。 - 改用 "nftables-multiport", "drop", "mode=aggressive"
创建文件 /etc/fail2ban/jail.local[sshd] enabled = true port = 22,2222 mode = aggressive #ignoreip=127.0.0.1/8 192.168.0.0/16 ignoreip=127.0.0.1/8 banaction=nftables-multiport[blocktype=drop] blocktype = drop findtime=600 # 一次ssh密码错产生3条匹配 maxretry=10 bantime=3600
- 或者直接改了缺省设置为 "nftables-multiport", "drop", "mode=aggressive"
创建文件 /etc/fail2ban/jail.local[DEFAULT] banaction = nftables-multiport[blocktype=drop] banaction_allports = nftables-allports [sshd] enabled = true port = 22,2222 mode = aggressive #ignoreip=127.0.0.1/8 192.168.0.0/16 ignoreip=127.0.0.1/8 findtime=600 maxretry=10 bantime=3600
ignorecommand = /bin/sh /pathto/mycheck.sh <ip>
可以提供一个脚本动态决定,是否要 ignore 这个IP。
看 fail2ban 的帮助,man jail.conf
。- 命令行,
打印出 服务的配置:fail2ban-server -d
。
手工添加 对"sshd"的 一个IP封禁:fail2ban-client set sshd banip 192.168.xx.xx
。
手工取消 对"sshd"的 IP封禁:fail2ban-client set sshd unbanip 192.168.xx.xx
。
获取 对"sshd"封禁的 IP列表:fail2ban-client get sshd banip
。 - 如果你重建系统的防火墙规则,flush 所有规则后重建,丢失 fail2ban建立的 table 和 chain。
无需重启 fail2ban,它会在需要的时候自动重建 nft 规则 (有时,1-5分钟后,就自动重建了)。
sshd 支持的加密算法
debian
- 2023-03 记录
- 可以去【Rebex SSH Check】,检测一下。就像 SSL的测试一样【SSL状态检测】。
介绍【How to Check the Security of the SSH Server and Protect it from Attacks】。 - 或者使用
nmap --script ssh2-enum-algos -sV -p 22 xx.xx.xx.xx
检测sshd支持的算法列表。 - 去掉 ssh-rsa 和 包含 "sha1", "64" 字样的弱算法。
- sshd_config 中去掉4个不太安全的 MAC消息验证算法。去掉 ssh-rsa。
MACs -umac-64-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-64@openssh.com,hmac-sha1 HostKeyAlgorithms -ssh-rsa PubkeyAcceptedKeyTypes -ssh-rsa
- 缺省
hostbasedauthentication no
,所以hostbasedacceptedkeytypes
可以不用改。 - 用命令检查一下,看
sshd -T
的输出中,对应上面的修改,减少了那几个算法。 service sshd reload|restart
重启服务生效。- 试试你常用的客户端,有没有因客户端太老,而登陆失败的。
centos8
- 2023-03 记录
- 修改
/etc/ssh/sshd_config
中有关算法的配置无效。Centos8 有关sshd算法的配置是在另一个单独文件中。
需要修改/etc/crypto-policies/back-ends/opensshserver.config
。
防火墙 限制连接数
- 目的:想通过防火墙,限制 ssh,每个IP,每分钟,新建连接的个数。已经建立的连接不受影响,不限制传输速度。
- 网上搜的各种做法,先抄下来。大部分都能执行不报错。
有的写法,并不是我希望的效果。
nft
- chain 的准备
下面的规则中,使用到的 chain: "ip filter input"。
如果系统已经有,就直接使用。如果没有就自己添加。
想用 chain: "inet filter input",也可以。自己创建。nft add table ip filter nft add chain ip filter input '{type filter hook input priority filter +5;}'
- 同时连接数,使用 ct count
# 这个有效,但应该是针对所有IP。限制同时10个在线 nft add rule ip filter input tcp dport 22 ct count 10 counter accept nft add rule ip filter input tcp dport 22 counter reject with tcp reset
# 加一个 set,就可以区分IP。限制每IP 5个在线。2023-03测试ok。 # 当 ssh_flood 中的某个IP连接数为 0时,记录会被自动删除 nft add set ip filter ssh_flood '{ type ipv4_addr; size 256; flags dynamic; }' nft add rule ip filter input tcp dport 22 add @ssh_flood '{ ip saddr ct count over 5 }' counter reject
- 使用 ct count 和 meter
【使用 nftables 限制连接数量】。有两个例子: 限制同时连接数 和 新建连接数。
centos8中的man nft
中的例子写的就是用meter方法。nft v0.9.3,kernel-4.18。
但 debian中的man nft
中的例子就没有meter方法。nft v0.9.8,kernel-5.10。
看【nftables Meters】,文章说meter已经过时。新版可能要废弃meter。 - 使用 limit。限制新建连接数。
【Nftables 示例】。nft add rule ip filter input tcp dport 22 ct state new limit rale 3/second log nft add rule ip filter input tcp dport 22 ct state new limit rate 15/minute accept nft add rule ip filter input tcp dport 22 ct state new drop # 这个有效,但它是针对所有IP的。每秒3个以上的记录,每分钟15个以上的拒绝。
- 最终,参考了
man nft
中的例子,使用了这套规则。kernel-5.10,nft-v0.9.8。
某个IP, 第一分钟内发起超过 35-40个连接,后续每分钟超过5个。就封禁 30分钟。2023-03测试ok。# 服务器用,可以把两个 set 都改 size 65536 nft add set ip filter flood '{ type ipv4_addr; size 1024; timeout 7m; flags dynamic; }' nft add set ip filter blackhole '{ type ipv4_addr; size 256; timeout 30m; flags dynamic; }' nft add rule ip filter input ct state { established,related } accept nft add rule ip filter input iifname "lo" accept nft add rule ip filter input ip saddr @blackhole tcp dport 22 ct state new counter drop # 下面这句中,用 update @flood,是为了更新对应ip的expires值。否则会以第一次加入set的时间倒计时。 nft add rule ip filter input tcp dport 22 ct state new update @flood { ip saddr limit rate over 5/minute burst 35 packets } add @blackhole { ip saddr } counter log prefix '"OVER_LIMIT:"' drop
- 另一个内核较旧的系统中 kernel-5.0,nft-v0.9.8。就不支持上面的规则。
不支持使用 dynamic 的 set作为规则判断,ip saddr @blackhole drop
。
测试发现,旧语法 meter,也能够更新 表中ip的 expires时间。
再测试发现,不是 dynamic的 set就能支持规则判断。最终写法如下。两种写法都测试OK(2023-03)。## 下面的一行前面加上 "nft add rule ip filter input",包含 {};双引号 的部分,要用反斜杠或单引号。 ct state { established,related } accept tcp dport 22 ct state new meter flood size 1024 { ip saddr timeout 7m limit rate over 5/minute burst 35 packets } counter reject # 效果是,第一分钟可以连40个,后续控制连接的速率 5个/分钟,但没有进一步的封禁。2023-03测试ok。
## 注: 无 dynamic属性的 set,添加元素时 不支持 limit语法。meter表的本质就是 dynamic的 set。 ## 下面的每一行前面加上 "nft add rule/set ip filter input",包含 {};双引号 的部分,要用反斜杠或单引号。 # 写法1。其实就是把 blackhole 的 dynamic属性去掉。 set flood { type ipv4_addr; size 1024; timeout 7m; flags dynamic; } set blackhole{ type ipv4_addr; size 256; timeout 30m; } ct state { established,related } accept ip saddr @blackhole tcp dport 22 ct state new counter drop tcp dport 22 ct state new update @flood { ip saddr limit rate over 5/minute burst 35 packets } add @blackhole { ip saddr } counter log prefix "OVER_LIMIT:" drop # 写法2,效果同写法1。去掉 blackhole的 dynamic属性,并且使用 meter语法。 set blackhole{ type ipv4_addr; size 256; timeout 30m; } ct state { established,related } accept ip saddr @blackhole tcp dport 22 ct state new counter drop tcp dport 22 ct state new meter flood size 1024 { ip saddr timeout 7m limit rate over 5/minute burst 35 packets } add @blackhole { ip saddr } counter log prefix "OVER_LIMIT:" drop
- centos8的系统中 kernel-4.18,nft-v0.9.3。2023-03测试OK。
# blackhole 有没有 dynamic属性都可以。但只能用 meter语法。 ## 下面的每一行前面加上 "nft add rule/set ip filter INPUT",包含 {};双引号 的部分,要用反斜杠或单引号。 set blackhole{ type ipv4_addr; size 256; timeout 30m; } ct state { established,related } accept ip saddr @blackhole tcp dport 22 ct state new counter drop tcp dport 22 ct state new meter flood size 1024 { ip saddr timeout 7m limit rate over 5/minute burst 35 packets } add @blackhole { ip saddr } counter log prefix "OVER_LIMIT:" drop
- 理解与解释,根据测试的结果推测的。如有不对,请指正。
token bucket filter,令牌桶。burst指定了 令牌初始值 和 桶的容量(令牌总数),limit定义了桶中的令牌恢复速度。
比如limit 6/minute burst 50 packets
,桶中的令牌初值是50,令牌每 10秒恢复一个,最多50个。
规则中,set flood
的 IP记录超时 被清除之后,这个 IP就恢复了初值 50。
所以,set flood
的 timeout,至少应该设置为 (burst/limit)。
即 50/(6/minute) = 8.33 minute。设置为 9m 或者 500s 。
set blackhole
的 timeout,自己随便设置,想封禁 5小时,就写 5h 。
iptables
- 限制同时连接数,即同时在线数。区分IP。2023-03测试可用。
#默认带有 --connlimit-saddr 和 --connlimit-mask 参数 iptables -I INPUT -p tcp --dport 2222 -m connlimit --connlimit-above 10 -j DROP
- 限制新建连接数
- 可以使用这套规则。这个会区分IP。限制60秒内10个新建连接。只是没有进一步的封禁。
# 默认带有 --rsource 参数 iptables -A INPUT -p tcp --dport 2222 --syn -m recent --name sshpool --rcheck --seconds 60 --hitcount 10 -j DROP iptables -A INPUT -p tcp --dport 2222 --syn -m recent --name sshpool --set -j ACCEPT # 2023-03测试可以用,iptables v1.8.2, nft v0.9.0 # 数据库文件在 /proc/net/xt_recent/sshpool
- 这个,基于令牌桶,但不区分IP。限制每分钟5个新连接,第一分钟允许50-55个。应该是所有IP共用一个令牌桶。
iptables -A INPUT -p tcp --dport 2222 -m conntrack --ctstate NEW -m limit --limit 5/minute --limit-burst 50 -j ACCEPT iptables -A INPUT -p tcp --dport 2222 -m conntrack --ctstate NEW -j DROP # 2023-03测试可用。(iptables v1.8.2 , nft v0.9.0) (iptables v1.8.4 , nft v0.9.3) # 对应的 nft 规则是 nft add rule ip filter input meta l4proto tcp tcp dport 2222 ct state new limit rate 5/minute burst 50 packets counter accept nft add rule ip filter input meta l4proto tcp tcp dport 2222 ct state new counter drop
- 建议用这套规则。也是基于令牌桶。这个会区分IP。限制每分钟5个新连接,第一分钟允许15-20个。只是没有进一步的封禁。
#有 --hashlimit-mode 就区分IP,没有这个参数就不区分IP iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m hashlimit --hashlimit-mode srcip --hashlimit-upto 5/minute --hashlimit-burst 15 --hashlimit-name conn_rate_limit --jump ACCEPT iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j DROP # 2023-03测试可用。(iptables v1.8.2 , nft v0.9.0) (iptables v1.8.4 , nft v0.9.3) (iptables v1.8.7 , nft v0.9.8) # 对应的 nft 规则是 nft add rule ip filter input meta l4proto tcp tcp dport 22 ct state new meter conn_rate_limit { ip saddr limit rate 5/minute burst 15 packets} counter accept nft add rule ip filter input meta l4proto tcp tcp dport 22 ct state new counter drop
- 可以使用这套规则。这个会区分IP。限制60秒内10个新建连接。只是没有进一步的封禁。