osnosn

  博客园 :: 首页 :: 博问 :: 闪存 :: :: 联系 :: 订阅 订阅 :: 管理 ::

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 { ... } }

安装配置 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通过密码登录

安装配置 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"。
    如果系统已经有,就直接使用。如果没有就自己添加。
    nft add table ip filter
    nft add chain ip filter input '{type filter hook input priority filter +5;}'
    
    想用 chain: "inet filter input",也可以。自己创建。
  • 同时连接数,使用 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。限制新建连接数。
    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个以上的拒绝。
    
    Nftables 示例】。
  • 最终,参考了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时间。
    ## 下面的一行前面加上 "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就能支持规则判断。最终写法如下。两种写法都测试OK(2023-03)。
    ## 注: 无 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 floodtimeout,至少应该设置为 (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
      

转载注明来源: 本文链接 来自osnosn的博客.

posted on 2020-11-07 14:48  osnosn  阅读(606)  评论(0编辑  收藏  举报