zoukankan      html  css  js  c++  java
  • Iptables 之recent模块小结

    Iptables的recent模块用于限制一段时间内的连接数, 是谨防大量请求攻击的必杀绝技! 善加利用该模块可充分保证服务器安全。

    recent常用参数
    --name      设定列表名称,即设置跟踪数据库的文件名. 默认DEFAULT;
    --rsource   源地址,此为默认。 只进行数据库中信息的匹配,并不会对已存在的数据做任何变更操作;
    --rdest       目的地址;
    --seconds  指定时间内. 当事件发生时,只会匹配数据库中前"几秒"内的记录,--seconds必须与--rcheck或--update参数共用;
    --hitcount   命中次数. hits匹配重复发生次数,必须与--rcheck或--update参数共用;
    --set           将地址添加进列表,并更新信息,包含地址加入的时间戳。 即将符合条件的来源数据添加到数据库中,但如果来源端数据已经存在,则更新数据库中的记录信息;
    --rcheck     检查地址是否在列表,以第一个匹配开始计算时间;
    --update    和rcheck类似,以最后一个匹配计算时间。 如果来源端的数据已存在,则将其更新;若不存在,则不做任何处理;
    --remove   在列表里删除相应地址,后跟列表名称及地址。如果来源端数据已存在,则将其删除,若不存在,则不做任何处理;

    recent模块需要注意的地方
    a)  目录/proc/net/下的xt_recent目录是在启用recent模块之后才有的,如果没有在iptables中使用recent模块,/proc/net/目录中是没有xt_recent目录的;
    b)  因recent模块最多只能记录20条记录,所以当源发送的数据包超过20后,recent模块的计数器会立刻减掉20,这也就是为什么old_packets的值就总是处于1-20之间;
    c)  如果配合seconds参数使用的是--rcheck参数而不是--update,则recent模块会从收到第一个数据包开始计算阻断时间,而--update是从收到的最后一个数据包开始计算阻断时间,即如果服务器在8点收到了源发出第一个icmp数据包,在8点15分收到源发出的第20个数据包,如果使用的是--rcheck参数,那么8点半的时候,用户就又可以发送icmp数据包了,如果使用是--update参数,则用户必须等到8点40才能发送icmp数据包;
    d)  当源发送数据包的个数大于或等于recent模块的hitcount参数所指定的值时,相应的iptables规则才会被激活;

    recent命令大体有如下三个排列组合
    --set句在前,--update(或--rcheck)句在后;
    --update(或--rcheck)句在前,--set句在后;
    --set句带或不带-j ACCEPT。基本是上面这三项的排列组合;

    下面通过几个案例进行说明
    1)  利用iptables的recent模块来抵御简单的DOS攻击, 下面以限制ssh远程连接为例

    iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 3 -j DROP
    iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH
    iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds  300 --hitcount 3 --name SSH -j DROP
    

    以上三条规则的解释如下:
    a) 利用connlimit模块将单IP的并发设置为3;会误杀使用NAT上网的用户,可以根据实际情况增大该值;
    b) 利用recent和state模块限制单IP在300s内只能与本机建立3个新连接。被限制一分钟后即可恢复访问。
    c) 第一句是记录访问tcp 22端口的新连接,记录名称为SSH, --set 记录数据包的来源IP,如果IP已经存在将更新已经存在的条目
    d) 第三句是指SSH记录中的IP,300s内发起超过3次连接则拒绝此IP的连接。
         --update 是指每次建立连接都更新列表;
         --seconds必须与--update同时使用
         --hitcount必须与--update同时使用
    e) 可以使用下面的这句记录日志:

    iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --name SSH --second 300 --hitcount 3 -j LOG --log-prefix "SSH Attack"
    

    recent模块可以看作iptables里面维护了一个地址列表,这个地址列表可以通过"--set"、"--update"、"--rcheck"、"--remove"四种方法来修改列表,每次使用时只能选用一种
    还可附带"--name"参数来指 定列表的名字(默认为DEFAULT),"--rsource"、"--rdest"指示当前方法应用到数据包的源地址还是目的地址(默认是前者)。recent语句都带有布尔型返回值,每次执行若结果为真,则会执行后续的语句,比如"-j ACCEPT"之类的。"--seconds"参数表示限制包地址被记录进列表的时间要小于等于后面的时间。

    基于上面的说明,现在来看四个基本方法的作用:
    --set       将地址添加进列表,并更新信息,包含地址加入的时间戳。
    --rcheck  检查地址是否在列表。
    --update  跟rcheck一样,但会刷新时间戳。
    --remove 就是在列表里删除地址,如果要删除的地址不存在就会返回假。

    例1:限制无法ssh直接连接服务器,需先用较大包ping一下,此时在15秒内才可以连接上

    iptables -P INPUT DROP
    iptables -A INPUT -s 127.0.0.1/32 -j ACCEPT
    iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
    iptables -A INPUT -p icmp --icmp-type 8 -m length --length 128 -m recent --set --name SSHOPEN --rsource -j ACCEPT
    iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT
    iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --rcheck --seconds 15 --name SSHOPEN --rsource -j ACCEPT

    以上命令解说
    a) 将INPUT链默认策略置为DROP,当包走完INPUT链而没被拿走时就会丢弃掉;
    b) 本地localhost的包全部接受;
    c)  对于已建立连接或是与已连接相关的包都接受,服务器对外连接回来的包一般都走这条;基本环境已经配好了,现在开始要为连接到服务器的ssh打开通路。
    d)  icmp类型8是ping包;指定包大小为128字节;recent用的列表名称为SSHOPEN,列表记录源地址。符合上述条件的数据包都接收。如果ping包内容为100字节,则加上IP      头, ICMP头的28字节,总共128字节。
    e) 接受一般的ping包;
    f)  对连接ssh 22端口的连接进行处理,来源于SSHOPEN源地址列表并且在列表时间小于等于15秒的才放行。

    例2:  限制每ip在一分钟内最多对服务器只能有8个http连接

    iptables -I INPUT -p tcp --dport 80 -d 192.168.10.10 -m state --state NEW -m recent --name httpuser --set
    iptables -A INPUT -m recent --update --name httpuser --seconds 60 --hitcount 9 -j LOG --log-prefix 'HTTP attack: '
    iptables -A INPUT -m recent --update --name httpuser --seconds 60 --hitcount 9 -j DROP

    以上命令解说
    a) 192.168.10.10是服务器ip
    b) 参数-I,将本规则插入到 INPUT 链里头的最上头。只要是 TCP连接,目标端口是80,目标 IP是我们服务器的IP,刚刚新被建立起来时,我们就将这个联机列入 httpuser 这分  清单中;
    c) 参数-A,将本规则附在 INPUT 链的最尾端。只要是60秒内,同一个来源连续产生多个联机,到达第9个联机时,我们对此联机留下Log记录。记录行会以 HTTP attack 开头。  每一次的本规则比对, –update 均会更新httpuser清单中的列表;
    d)  参数-A,将本规则附在 INPUT 链的最尾端。同样的比对条件,但是本次的动作则是将此连接丢掉;
    e) 所以,这三行规则表示,我们允许一个客户端,每一分钟内可以接上服务器8个。具体数值可以看运维者决定。这些规则另外也可以用在其它对外开放的网络服务上,例如port  22 (SSH), port 25 (smtp email)。

    2) 对连接到服务器B的SSH连接进行限制,每个IP每小时只限连接5次

    -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name SSHPOOL --rcheck --seconds 3600 --hitcount 5 -j DROP
    -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name SSHPOOL --set -j ACCEPT
    

    服务器A连接服务器B的SSH服务的数据包流程,假设以下数据包是在一小时(3600秒)内到达服务器B(iptables配置如上)的:
    a) 当这个服务器A的第1个SSH包到达服务器B,规则1检查SSHPOOL列表中这个源IP是否有hitcount,因为是第一个包,显而易见,列表是0,规则1判定这个数据包不必执行      DROP,并且也不处理这个数据包,将数据包转给下条规则。
    b) 规则2将这个数据包计入SSHPOOL列表,就是做+1,因为规则中有-j ACCEPT,规则2放行这个包。
    c) 第1个数据包进入服务器B,不用再在iptables里转了。
    d) 当第2个SSH包到达服务器B,规则1检查SSHPOOL列表的hitcount,发现是1没有超过5,于是判定不执行DROP并转给下条规则处理。
    e) 规则2在SSHPOOL中+1,并放行,第2个数据包进入服务器B。
    f) 第3、4、5个包同上。
    g) 第6个包到达服务器B,规则1检查SSHPOOL列表中的hitcount,发现是5了已经连接5次了,于是规则2执行DROP,不必再转给下条规则了丢弃该包。
    h) 第7、8…个包同上。

    实际上recent的处理更为复杂, 从上面的流程可以看出,--set的功能在于计录数据包,将源IP加入列表。--rcheck(update)的功能在于判定数据包在seconds和hitcount条件下是否要DROP。

    如果采用下面的配置, 则必须在INPUT链的默认策略为ACCEPT的情况下才能生效并使用, 否则(即INPUT链的默认策略为DROP)所有的SSH包都被丢弃了!!!!

    -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT                            //必须添加这个前提条件才能生效!
    -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name SSHPOOL --set
    -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name SSHPOOL --rcheck --seconds 3600 --hitcount 5 -j DROP
    

    这个命令与上面命令的区别在于:set句在前,且set句不带-j ACCEPT。这导致数据包的流程也不同。
    a) 第1个数据包到达规则1后马上计入SSHPOOL列表,并且规则1因为没有-j ACCEPT,直接将数据包转给下条规则。规则2拿到这个数据包后检查SSHPOOL列表,发现是1,也  不处理这个包,转给下条规则。如果后续的规则都没有再处理这个数据包,则最后由INPUT链的默认策略ACCEPT处理。由于上面的策略是DROP,所以丢弃该包,于是这两行命令在我的服务器上不能用。
    b) 这里有个问题,由于set句在前,数据包进入是先计入列表,再判定是否合法。这导致第5个包到达后,先在列表中+1,结果是5,再由规则2判定,发现是5,结果丢弃该包,    最后真正ACCEPT的只有4个包。其实个人认为这样写的代码不符合正常的思维逻辑, 而且这样写只能正常工作于默认策略是ACCEPT的情况,所以不建议用这个版本的命令,我的版本ACCEPT、DROP策略都能用。

    从上面可以看出,在使用recent模块的命令的时候,一定要先确认iptables的INPUT链的默认策略是什么。

    接着说下--rcheck 和 --update的区别
    --rcheck从第1个包开始计算时间,--update是在rcheck的基础上增加了从最近的DROP包开始计算阻断时间,具有准许时间和阻断时间,update会更新last-seen时间戳。

    就拿上面那个配置案例来说, rcheck是接收到第1个数据包时开始计时,一个小时内仅限5次连接,后续的包丢弃,直到一小时过后又可以继续连接。update则是接收到第1个数据包时计算准许时间,在一个小时的准许时间内仅限5次连接,当有包被丢弃时,从最近的丢弃包开始计算阻断时间,在一个小时的阻断时间内没有接收到包,才可以继续连接。所以rcheck类似令牌桶,一小时给你5次,用完了抱歉等下个小时吧。update类似网银,连续输错5次密码,停止一小时,只不过update更严格,阻断时间是从最近的一次输错时间开始算,比如输错了5次,过了半个小时又输错一次,这时阻断时间不是剩半小时,而是从第6次重新计算,剩一小时. 

    可以拿下面这个命令进行测试, 自行替换rcheck、update,然后ping一下就明白了:

    -A INPUT -p icmp -m recent --name PINGPOOL --rcheck --seconds 30 --hitcount 5 -j DROP
    -A INPUT -p icmp -m recent --name PINGPOOL --set -j ACCEPT
     
    -A INPUT -p icmp -m recent --name PINGPOOL --update --seconds 30 --hitcount 5 -j DROP
    -A INPUT -p icmp -m recent --name PINGPOOL --set -j ACCEPT
    

    温馨提示:
    ICMP包和UDP包在iptables中的state情况是一样的,因为是无状态的,不同于TCP,iptables可以靠SYN等flags确定state,而iptables是基于ICMP包/UDP包到达服务器的间隔时间来确定state的。比如在做上面测试的时候,使用ping 192.168.10.10 -t时,除了第一个ICMP包state是NEW,后续的包state都是ESTABLISHED,结果因为前面有一句:

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

    结果测试ping一直是通的,这个一定要弄明白!

    3) 限制80端口60秒内每个IP只能发起10个新连接,超过记录日记及丢失数据包,可防CC及非伪造IP的syn flood

    iptables -A INPUT -p tcp --dport 80 --syn -m recent --name webpool --rcheck --seconds 60 --hitcount 10 -j LOG --log-prefix 'DDOS:' --log-ip-options
    iptables -A INPUT -p tcp --dport 80 --syn -m recent --name webpool --rcheck --seconds 60 --hitcount 10 -j DROP
    iptables -A INPUT -p tcp --dport 80 --syn -m recent --name webpool --set -j ACCEPT
    

    以上命令解说
    第1行规则表示: 60秒10个新连接,超过记录日志。
    第2行规则表示: 60秒10个新连接,超过记录日志。
    第3行规则表示: 范围内允许通过。
    即每个IP目标端口为80的新连接会记录在案,可在/proc/net/xt_recent/目录内查看,rcheck检查此IP是否在案及请求次数,如果超过规则就丢弃数据包,否则进入下条规则并更新列表信息。

    发送特定指定执行相应操作,按上面设置, 如果自己IP被阻止了,可设置解锁。

    iptables -A INPUT -p tcp --dport 5000 --syn -j LOG --log-prefix "WEBOPEN: "
    #记录日志,前缀WEBOPEN:
    iptables -A INPUT -p tcp --dport 5000 --syn -m recent --remove --name webpool --rsource -j REJECT --reject-with tcp-reset
    #符合规则即删除webpool列表内的本IP记录
    

    4)  默认封闭SSH端口,为您的SSH服务器设置开门暗语

    iptables -A INPUT -p tcp --dport 50001 --syn -j LOG --log-prefix "SSHOPEN: "
    #记录日志,前缀SSHOPEN:
    iptables -A INPUT -p tcp --dport 50001 --syn -m recent --set --name sshopen --rsource -j REJECT --reject-with tcp-reset
    #目标端口tcp 50001的新数据设定列表为sshopen返回TCP重置,并记录源地址。
    iptables -A INPUT -p tcp --dport 22 --syn -m recent --rcheck --seconds 15 --name sshopen --rsource -j ACCEPT
    #开启SSH端口,15秒内允许记录的源地址登录SSH。
     
    #开门钥匙
    nc host 50001 
    telnet host 50001
    nmap -sS host 50001
    

    5) 指定端口容易被破解密钥,可以使用ping指定数据包大小为开门钥匙

    iptables -A INPUT -p icmp --icmp-type 8 -m length --length 78 -j LOG --log-prefix "SSHOPEN: "
    #记录日志,前缀SSHOPEN:
    iptables -A INPUT -p icmp --icmp-type 8 -m length --length 78 -m recent --set --name sshopen --rsource -j ACCEPT
    #指定数据包78字节,包含IP头部20字节,ICMP头部8字节。
    iptables -A INPUT -p tcp --dport 22 --syn -m recent --rcheck --seconds 15 --name sshopen --rsource -j ACCEPT
    

    安装上面配置后, 依然无法ssh登录到指定主机, 因为没有添加"INPUT链的默认策略为ACCEPT"的前提, 即需要下面这个前提条件!

    iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
    

    整理后的配置规则

    iptables -F
    iptables -X
    iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
    iptables -A INPUT -p icmp --icmp-type 8 -m length --length 78 -j LOG --log-prefix 'SSH_OPEN_KEY'
    iptables -A INPUT -p icmp --icmp-type 8 -m length --length 78 -m recent --name openssh --set --rsource -j ACCEPT
    iptables -A INPUT -p tcp --dport 22 --syn -m state --name openssh --rcheck --seconds 60 --rsource -j ACCEPT
    iptables -P INPUT DROP
    
    针对上面整理后的配置规则说明
    第1,2行规则表示: 清空原有的iptables规则
    第3行规则表示: 已经建立成功的连接和与主机发送出去的包相关的数据包都接受,如果没有这一步,后面的tcp连接无法建立起来
    第4行规则表示: 出现长度为78字节icmp回响包在/var/log/syslog生成log,log以SSH_OPEN_KEY开头
    第5行规则表示: 出现长度为78字节icmp回响包,将源地址信息记录在openssh文件中,并接受
    第6行规则表示: 对于openssh文件中的源地址60s以内发送的ssh连接SYN请求予以接受
    第7行规则表示: 将INPUT链的默认策略设置为drop

    调试过程:
    a) 如果没有设置第3行规则,则无法建立ssh连接
    b) 在没有第3行规则的情况下,设置第6行如果不加--syn,则可以ssh连接一会儿,过一会儿又自动断线,除非ping一下目的地址.
    原理是:ping目的地址,则会更新openssh的时间,这样ssh连接还在60s之内,所以可以通信,过一会儿,60s超时,则就会断开ssh连接。如果加了--syn,只能进行开始的syn,无法正常连接

    在客户机上,如果需要ssh到主机,需要先ping主机进行解锁

    ping -s 50 ip    #linux主机的ip
    ping -l 50 ip     #windows主机的ip
    

    并在一分钟之内ssh到主机,这样在/proc/net/xt_recent/目录下生成openssh文件, 内容如下:

    src=192.168.10.10
    ttl: 53
    last_seen: 42963x6778
    oldest_pkt: 1 4296376778, 4295806644, 4295806895, 4295807146, 4295826619, 4295826870, 4295827122, 4295827372, 4295833120, 4295833369, 4295834525, 4295834777, 4295872016, 4295872267, 4295872519, 4295872769, 4295889154, 4295889406, 4295889658, 4295889910
  • 相关阅读:
    2021秋 数分B1笔记
    android逆向奇技淫巧二十三:自己写app调用x音关键so(未完待续)(八)
    android逆向奇技淫巧二十二:ida栈回溯加密算法跟踪(未完待续)(七)
    http tcp websocket
    location.reload
    event.preventDefault
    document.querySelector
    造成播放端卡顿的原因
    引入外部组件 Vue.use()和Vue.component()
    Interpolation
  • 原文地址:https://www.cnblogs.com/kevingrace/p/10008487.html
Copyright © 2011-2022 走看看