iptables技巧与窍门


60

我确信Linux系统管理员iptablesnetfilter数据包过滤框架的userland接口非常熟悉。

现在,此“问题”旨在成为一个社区Wiki,用于收集各种iptables智慧元素。没有什么太普遍或太晦涩。发表任何您知道会帮助他人充分利用的信息iptables

Answers:


26

将白名单和黑名单与iptables一起使用

#!/bin/bash

WHITELIST=/whitelist.txt
BLACKLIST=/blacklist.txt

#THIS WILL CLEAR ALL EXISTING RULES!
echo 'Clearing all rules'
iptables -F

#
## Whitelist
#

for x in `grep -v ^# $WHITELIST | awk '{print $1}'`; do
        echo "Permitting $x..."
        $IPTABLES -A INPUT -t filter -s $x -j ACCEPT
done

#
## Blacklist
#

for x in `grep -v ^# $BLACKLIST | awk '{print $1}'`; do
        echo "Denying $x..."
        $IPTABLES -A INPUT -t filter -s $x -j DROP
done

打开端口的脚本

#!/bin/bash
ALLOWEDTCP="80 3128 3784"
ALLOWEDUDP="3128 3784"

#
## Permitted Ports
#

for port in $ALLOWEDTCP; do
       echo "Accepting port TCP $port..."
       $IPTABLES -A INPUT -t filter -p tcp --dport $port -j ACCEPT
done

for port in $ALLOWEDUDP; do
        echo "Accepting port UDP $port..."
        $IPTABLES -A INPUT -t filter -p udp --dport $port -j ACCEPT
done

阻塞端口

# Attempt to block portscans
# Anyone who tried to portscan us is locked out for an entire day.
iptables -A INPUT   -m recent --name portscan --rcheck --seconds 86400 -j DROP
iptables -A FORWARD -m recent --name portscan --rcheck --seconds 86400 -j DROP

# Once the day has passed, remove them from the portscan list
iptables -A INPUT   -m recent --name portscan --remove
iptables -A FORWARD -m recent --name portscan --remove

# These rules add scanners to the portscan list, and log the attempt.
iptables -A INPUT   -p tcp -m tcp --dport 139 -m recent --name portscan --set -j LOG --log-prefix "Portscan:"
iptables -A INPUT   -p tcp -m tcp --dport 139 -m recent --name portscan --set -j DROP

iptables -A FORWARD -p tcp -m tcp --dport 139 -m recent --name portscan --set -j LOG --log-prefix "Portscan:"
iptables -A FORWARD -p tcp -m tcp --dport 139 -m recent --name portscan --set -j DROP

欺骗/无效数据包

# Reject spoofed packets
# These adresses are mostly used for LAN's, so if these would come to a WAN-only server, drop them.
iptables -A INPUT -s 10.0.0.0/8 -j DROP
iptables -A INPUT -s 169.254.0.0/16 -j DROP
iptables -A INPUT -s 172.16.0.0/12 -j DROP
iptables -A INPUT -s 127.0.0.0/8 -j DROP

#Multicast-adresses.
iptables -A INPUT -s 224.0.0.0/4 -j DROP
iptables -A INPUT -d 224.0.0.0/4 -j DROP
iptables -A INPUT -s 240.0.0.0/5 -j DROP
iptables -A INPUT -d 240.0.0.0/5 -j DROP
iptables -A INPUT -s 0.0.0.0/8 -j DROP
iptables -A INPUT -d 0.0.0.0/8 -j DROP
iptables -A INPUT -d 239.255.255.0/24 -j DROP
iptables -A INPUT -d 255.255.255.255 -j DROP

# Drop all invalid packets
iptables -A INPUT -m state --state INVALID -j DROP
iptables -A FORWARD -m state --state INVALID -j DROP
iptables -A OUTPUT -m state --state INVALID -j DROP

阻止蓝精灵攻击

# Stop smurf attacks
iptables -A INPUT -p icmp -m icmp --icmp-type address-mask-request -j DROP
iptables -A INPUT -p icmp -m icmp --icmp-type timestamp-request -j DROP
iptables -A INPUT -p icmp -m icmp -j DROP

# Drop excessive RST packets to avoid smurf attacks
iptables -A INPUT -p tcp -m tcp --tcp-flags RST RST -m limit --limit 2/second --limit-burst 2 -j ACCEPT

阻止ICMP(aka Ping)

# Don't allow pings through
iptables -A INPUT -p icmp -m icmp --icmp-type 8 -j DROP

4
考虑在“欺骗”注释中添加注释,以便经验不足的用户知道为什么将源地址视为欺骗(...到达wan接口时)。
3molo 2011年

1
好决定 :-)。做完了
Bart De Vos

等待。Block ICMP(aka ping)行是否对Block smurf攻击行来说是多余的:iptables -A INPUT -p icmp -m icmp -j DROP?
斯坦

2
重新加入白名单脚本:iptables在第8行上,然后再行$IPTABLES。仅在iptables任何地方使用就足够了吗?否则我想您需要分配类似IPTABLES=/sbin/iptables权利的东西?
UpTheCreek

1
我不会以这种方式阻止portcans。而是要有一些可以接受tcp / udp连接并寻找多个相关数据包的东西。tcp很简单,只需查找已建立的端口即可。其他任何事情,其他人都可以使用欺骗性数据包进行测试,并阻止您未列入白名单的任何内容,例如网关。
亚伦

25

使用优化网络过滤器的性能 ipset

如果您仅基于IP,端口或同时基于这两者编写了许多类似的规则,请考虑使用ipset来优化netfilter的性能。

例如:

iptables -s 192.168.1.11 -j ACCEPT
iptables -s 192.168.1.27 -j ACCEPT
iptables -s 192.168.1.44 -j ACCEPT
... hundreds of similar rules ...
iptables -s 192.168.251.177 -j ACCEPT

这意味着源地址为192.168.251.177的数据包必须先遍历数百条规则,然后才能得出接受ACCEPT的结论。

当然,经验丰富的系统管理员会按子网划分规则。但这仍然意味着数百条规则。

ipset 营救!

首先,定义一个IP集ipmap类型:

ipset -N Allowed_Hosts ipmap --network 192.168.0.0/16

然后,用地址填充它:

for ip in $LIST_OF_ALLOWED_IP; do ipset -A Allowed_Hosts $ip; done

最后,用一个规则替换上面的数百个iptables规则:

iptables -m set --match-set Allowed_Hosts src -j ACCEPT

当数据包到达时,netfilter将根据IP集对数据包的源(src)IP 执行非常快速的位图搜索Allowed_Hosts。来自192.168.0.0/16的所有数据包都将遵循一条规则。并且一定要相信我,搜索位图至少比执行数百个iptables规则检查快两个数量级。

ipset不限于IP地址。它还可以根据端口,IP端口元组,网络/子网地址,IP-MAC元组等进行匹配。它可以将这些条件匹配为源或目标,或两者的混合(在元组的情况下)。

最后,ipset您可以自动将IP地址放入黑名单/白名单。这些黑名单/白名单也可以“老化”,从而在经过可配置的时间后自动删除IP地址。

有关更多详细信息,请参见ipset的手册页

重要提示:

某些Linux发行版可能提供“现成的”支持ipset(例如,Ubuntu 10.04出现了此问题)。在这些系统上,一种方法是ipset从源代码安装。

而是ipset从其网站下载的源:http : //ipset.netfilter.org/install.html

另外,如果你使用xtables-addons,IPSET 包含在它的源:http://xtables-addons.sourceforge.net/


3
真可惜,Debian和Ubuntu默认不支持。我以为你会列出一些令人发指的发行版:/
UpTheCreek

@UpTheCreek我已经编辑了答案...“特别说明”在发布答案期间适用,但现在不再适用。
pepoluan 2014年

21

在规则中添加注释:

-m comment --comment "Comments help to read output of iptables -nvL"

16

阻止众所周知的TCP攻击

添加以下规则,最好在 -t raw -A PREROUTING

-p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
-p tcp --tcp-flags SYN,RST SYN,RST -j DROP
-p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,PSH,URG -j DROP
-p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN -j DROP
-p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
-p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP

被阻止的攻击分别是:

  • SYN-FIN攻击
  • SYN-RST攻击
  • X-Mas攻击
  • nmap FIN扫描
  • NULLflags攻击
  • ALLflags攻击

(可以随意编辑以上攻击的名称)


4
-p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG FIN,SYN,RST,PSH,ACK,URG -j DROP可以被删除,因为-p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP会抓住每一个包时,它可以阻止。

4
根据security.stackexchange.com/questions/4603/…。“没有必要丢弃无效或格式错误的数据包,所有这些攻击已使用了十年之久。Linux内核开发人员比哪种类型的数据包有效和无效的更新得多。”“未来的缺陷如何?” ,有些人可能会争辩。那么,您如何知道将来的缺陷将在TCP处理程序中,而不是在iptables TCP解析器中?”
马特

1
理论上,@ VlastimilBurian 不再需要它们。但是添加这些规则集既不会减慢网络速度,也不会增加CPU负载,因此我认为没有理由不添加它们而忘记它们了
pepoluan

7

启用NAT

  1. echo 1 > /proc/sys/net/ipv4/ip_forward
  2. /sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

步骤1设置内核参数以允许ip转发,步骤2设置iptables规则,该规则在接口eth0上启用NAT。


4
那不会通过重启来持久,对吗?您需要编辑/etc/sysctl.conf net.ipv4.ip_forward = 1。(假设使用Red Hat或衍生产品。)
Aaron Copley

6

阻止ICMP攻击

添加以下规则,最好在 -t raw -A PREROUTING

-p icmp -m u32 ! --u32 "4&0x3FFF=0"   -j DROP
-p icmp -m length --length 1492:65535 -j DROP

第一条规则阻止“碎片标记”不为0的所有ICMP数据包。(ICMP 永远不应分段;它们应携带小的有效载荷)

第二条规则阻止过大的未分段的ICMP数据包。


那不会打破MTU发现路径吗?
马特

@Matt否,因为路径MTU发现仅使用与以太网有效负载大小一样大的数据包,即1500字节,其中8字节由IP头和ICMP头使用。
pepoluan 2015年

感谢您的澄清,但是1492-64k吗?为什么不是1500-65k。对于PPPoE,我可以理解1492,但可以直接使用以太网。
马特

这仍然适用吗?
LinuxSecurityFreak

@VlastimilBurian我会说是的。仍然不需要超大的ICMP数据包。
pepoluan '16

4

使用FireHOL-方便的iptables包装器

我发现它比直接iptables命令直观得多。特别是对于有过使用其他防火墙经验的人:

FireHOL是iptables防火墙生成器,它在具有任意数量的网络接口,任意数量的路由,任意数量的服务,任意数量的服务变化之间的复杂性(包括正负)的Linux主机和路由器上生成有状态iptables包过滤防火墙表达式)。


2
我更喜欢主动开发的Shorewall,它支持IPv4和IPv6,并且可以为其他iptables系统生成防火墙。
BillThor

4

(从我的iptables_tricks.txt文件中,从很多地方重新编译过:P)

使iptables在端口22(SSH)上来自同一IP的新连接之间等待15秒:

 iptables -A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --update --seconds 15 -j DROP
 iptables -A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --set -j ACCEPT

1
相同,但包括尝试次数:-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 5 --rttl --name SSH -j DROP
alexm 2011年


3

重新访问IP集

已经有一个提到IP集的答案。但是,它是一维的,因为它着重于经典规则的性能提升以及IP设置缓解了人们拥有的大量IP地址无法用CIDR表示法轻易地表示为子网的问题。

下面使用的符号

因为ipset我将使用读取ipset restore和写入的符号ipset save

对应于iptables(和ip6tables)规则,我将使用读取iptables-restore和写入的表示法iptables-save。这样可以简化符号,并让我突出显示潜在的仅IPv4(带前缀-4)或仅IPv6(带前缀-6)规则。

在某些示例中,我们会将数据包流转移到另一个链中。假定该链存在于该点,因此不会生成用于创建链的行(也未提及表名或COMMIT末尾的命令-ted)。

高级IP集

IP集可以做的比其他答案中提到的要多得多,除了这里的简短条目之外,您还应该阅读IP集文档(ipset(8)iptables-extensions(8)

例如,我会主要集中在三个集类型:hash:iphash:netlist:set,但更多的是比它们都具有有效的用例。

例如,您还可以匹配端口号,而不仅仅是IP地址

iptables-save和保存和还原IP集iptables-restore

您可以批量创建IP集声明,并将它们通过管道导入到中ipset restore。如果要使命令对已有的条目更具弹性,请使用ipset -exist restore

如果您的规则位于一个名为的文件中,则default.set可以使用:

ipset -exist restore < default.set

这样的文件可以包含要create设置的add条目和其中的条目。但是通常大多数命令行命令似乎在文件中都有相应的版本。示例(创建一组DNS服务器):

create dns4 hash:ip family inet
create dns6 hash:ip family inet6
# Google DNS servers
add dns4 8.8.8.8
add dns4 8.8.4.4
add dns6 2001:4860:4860::8888
add dns6 2001:4860:4860::8844

这里为IPv4(dns4)创建了一组,为IPv6(dns6)创建了一组。

IP超时

IP集合中的超时可以设置为每个集合以及每个条目的默认值。这在您要临时阻止某人的情况下非常有用(例如,用于端口扫描或尝试强行使用SSH服务器)。

其工作方式如下(创建IP集期间的默认设置):

create ssh_loggedon4 hash:ip  family inet  timeout 5400
create ssh_loggedon6 hash:ip  family inet6 timeout 5400
create ssh_dynblock4 hash:ip  family inet  timeout 1800
create ssh_dynblock6 hash:ip  family inet6 timeout 1800

我们将在下面返回这些特定的集合,以及为什么要按原样设置它们的理由。

如果您想为特定的IP地址设置超时时间,则可以简单地说:

add ssh_dynblock4 1.2.3.4 timeout 7200

将IP 1.2.3.4阻止两个小时,而不是(设置的)默认半小时。

如果ipset save ssh_dynblock4过一会儿再看,您会发现类似以下内容:

create ssh_dynblock4 hash:ip family inet hashsize 1024 maxelem 65536 timeout 1800
add ssh_dynblock4 1.2.3.4 timeout 6954

超时警告

  • 超时是任何给定集合的功能。如果未使用超时支持创建集合,则会收到错误消息(例如Kernel error received: Unknown error -1)。
  • 超时以秒为单位。例如,使用Bash算术表达式可以使分钟数达到秒。例如:sudo ipset add ssh_dynblock4 1.2.3.4 timeout $((120*60))

检查给定IP集中是否存在条目

在脚本内部,查看条目是否已存在可能很有用。可以实现ipset test这一点,如果该条目存在,则返回零,否则返回非零。因此,通常的检查可以在脚本中应用:

if ipset test dns4 8.8.8.8; then
  echo "Google DNS is in the set"
fi

但是,在许多情况下,您宁愿使用-existswitch ipset来指示它不要抱怨现有条目。

iptables规则中填充IP集

我认为,这是IP集的杀手级功能之一。您不仅可以与IP集的条目进行匹配,还可以将新条目添加到现有IP集。

例如,在此问题的答案中,您有:

-A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --update --seconds 15 -j DROP
-A INPUT -p tcp -i eth0 -m state --state NEW --dport 22 -m recent --set -j ACCEPT

...旨在限制对SSH(TCP端口22)的连接尝试的速率。使用的模块recent跟踪最近的连接尝试。但是state,我更喜欢conntrack模块而不是模块。

# Say on your input chain of the filter table you have
   -A INPUT -i eth+ -p tcp --dport ssh -j SSH
# Then inside the SSH chain you can
# 1. create an entry in the recent list on new connections
   -A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
# 2. check whether 3 connection attempts were made within 2 minutes
#    and if so add or update an entry in the ssh_dynblock4 IP set
-4 -A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock4 src --exist
-6 -A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock6 src --exist
# 3. last but not least reject the packets if the source IP is in our
#    IP set
-4 -A SSH -m set --match-set ssh_dynblock4 src -j REJECT
-6 -A SSH -m set --match-set ssh_dynblock6 src -j REJECT

在这种情况下,我会将流程重定向到SSH链,这样我就不必-p tcp --dport ssh为每个规则重复自己。

重申:

  • -m setiptables知道,我们用的开关从set模块(负责处理IP套)
  • --match-set ssh_dynblock4 src告诉iptablessrc)地址与命名集(ssh_dynblock4) 相匹配
    • 这对应于sudo ipset test ssh_dynblock4 $IP(其中$IP包含数据包的源IP地址)
  • -j SET --add-set ssh_dynblock4 src --exist从数据包中添加或更新src)地址到IP集中ssh_dynblock4。如果存在一个条目(--exist),它将被简单地更新。
    • 这对应于sudo ipset -exist add ssh_dynblock4 $IP(其中$IP包含数据包的源IP地址)

如果您想匹配目标/目标地址,请使用dst代替src。有关更多选项,请查阅手册。

套套

IP集可以包含其他集。现在,如果您一直关注本文,您会想知道是否可以组合集合。当然是。对于上面的IP集,我们可以创建两个联合集ssh_dynblockssh_loggedon分别包含仅IPv4和仅IPv6集:

create ssh_loggedon4 hash:ip  family inet  timeout 5400
create ssh_loggedon6 hash:ip  family inet6 timeout 5400
create ssh_dynblock4 hash:ip  family inet  timeout 1800
create ssh_dynblock6 hash:ip  family inet6 timeout 1800
# Sets of sets
create ssh_loggedon  list:set
create ssh_dynblock  list:set
# Populate the sets of sets
add ssh_loggedon ssh_loggedon4
add ssh_loggedon ssh_loggedon6
add ssh_dynblock ssh_dynblock4
add ssh_dynblock ssh_dynblock6

接下来要想到的问题是,这是否允许我们以 IP版本无关的方式匹配和操作IP集。

答案是肯定的是的!(ala,我上次检查时没有明确记录)

因此,上一节中的规则可以重写为:

-A INPUT -i eth+ -p tcp --dport ssh -j SSH
-A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
-A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock src --exist
-A SSH -m set --match-set ssh_dynblock src -j REJECT

这更加简洁。是的,这是经过尝试和测试的,它就像一种魅力。

放在一起:SSH蛮力防御

在我的服务器上,我有一个脚本作为cron作业运行,该脚本需要一堆主机名并将其解析为IP地址,然后将其输入到“可信主机”的IP集中。这个想法是,受信任的主机会尝试更多登录到服务器,并且不必像其他任何人一样被阻止出去。

相反,除了受信任主机的(潜在)例外(即规则顺序很重要)之外,我阻止了整个国家/地区连接到我的SSH服务器。

但是,这留给读者练习。在这里,我想添加一个整洁的解决方案,该解决方案将使用集合中包含的ssh_loggedon集合来允许进行后续的连接尝试,而不会受到与其他数据包相同的审查。

请注意以下规则,记住默认的超时时间为90分钟ssh_loggedon和30分钟,这一点很重要:ssh_dynblockiptables

-A INPUT -i eth+ -p tcp --dport ssh -j SSH
-A SSH -m set --match-set ssh_loggedon src -j ACCEPT
-A SSH -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A SSH -m conntrack --ctstate NEW -m recent --set --name tarpit
-A SSH -m conntrack --ctstate NEW -m recent --rcheck --seconds 120 --hitcount 3 --name tarpit -j SET --add-set ssh_dynblock src --exist
-A SSH -m set --match-set ssh_dynblock src -j REJECT

现在,您应该问自己,连接IP地址在ssh_loggedon子集中是如何结束的。所以请继续阅读...

奖励:添加您在SSH登录期间使用的IP

如果您尝试了sshrc和朋友,您将了解到它的缺点。但是PAM可以提供帮助。名为模块的模块pam_exec.so使我们可以在SSH登录期间调用一个脚本,该操作使我们知道该用户已被允许进入。

在和条目/etc/pam.d/sshd下方pam_envpam_selinux添加以下行:

session    optional     pam_exec.so stdout /path/to/your/script

并确保您的脚本版本(/path/to/your/script上面)存在并且可以执行。

PAM使用环境变量来传达正在发生的事情,因此您可以使用这样的简单脚本:

#!/bin/bash
# When called via pam_exec.so ...
SETNAME=ssh_loggedon
if [[ "$PAM_TYPE" == "open_session" ]] && [[ -n "$PAM_RHOST" ]]; then
    [[ "x$PAM_RHOST" != "x${PAM_RHOST//:/}" ]] && SETNAME="${SETNAME}6" || SETNAME="${SETNAME}4"
    ipset -exist add $SETNAME "$PAM_RHOST"
fi

不幸的是,该ipset实用程序似乎没有内置的netfilter智能。因此,在添加条目时,我们需要区分IPv4和IPv6 IP集。否则ipset将假定我们要向该组集合中添加另一而不是IP。当然,不太可能会有一个以IP命名的集合:)

因此,在这种情况下(否则),我们将检查:IP地址并追加6到设置名称中4

结束。


2

可以用来配置iptables的另一个GUI是Firewall Builder。它使用户可以将规则元素创建为数据库中的对象,然后将这些对象拖放到规则编辑器中以创建所需的防火墙策略。然后,应用程序将生成一个脚本文件,其中包含实施规则所需的所有iptables命令。

与某些其他iptables GUI解决方案不同,后者只能一次管理一个iptables配置,而使用Firewall Builder,您可以从单个应用程序管理大量的iptables配置。Firewall Builder在Linux,Windows和Mac OS X上运行,已经存在了10多年,并且在全球拥有成千上万的活跃用户。

全面披露-我是NetCitadel的联合创始人,NetCitadel是开发Firewall Builder的公司。


1

使用uid记录传出连接

iptables -A OUTPUT -m state --state NEW -m tcp -p tcp -m limit --limit 5/m -j LOG --log-uid --log-prefix="outgoing connection: "

端口/连接转发:

iptables -A PREROUTING -t nat -i eth1 -p tcp --dport 80 -j DNAT --to 10.0.1.7:80
iptables -A INPUT -p tcp -m state --state NEW --dport 80 -i eth1 -j ACCEPT

1
我更喜欢NFLOG目标。它允许使用更长的行前缀,并且用户模式守护程序也可以登录数据库。
0xC0000022L15

1

使用通配符匹配多个接口名称

示例:您有eth0 eth1想要允许它们之间的任何流量?

iptables -A FORWARD -i eth+ -o eth+ -j ACCEPT

我过去曾使用过此命令,以匹配veth<something>由LXC动态创建和命名的接口。因此,我可以一次将所有匹配veth+

我还特意命名了一些接口_<something>以与匹配_+


1

阻止不常见的MSS值

iptables -t mangle -A PREROUTING -p tcp \
-m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP

用于DDos保护的SYNPROXY目标

此目标的目的是检查发送SYN数据包的主机是否建立了连接,或者在启动SYN连接之后不执行任何操作。如果不执行任何操作,它将以最小的努力丢弃该数据包。

将syn数据包设置到原始表中的连接跟踪表

iptables -t raw -A PREROUTING -p tcp -m tcp --dport 80 --syn -j CT --notrack

为http服务器启用synproxy:

iptables -A INPUT -p tcp -m tcp --dport 80 -m conntrack --ctstate INVALID,UNTRACKED \
-j SYNPROXY --sack-perm --timestamp --wscale 7 --mss 1460

资源: RHEL博客中的SYNPROXY目标


1

使用IP集将所有单个IP地址限制为出站带宽配额

您可能需要将服务器配置为每个月仅允许每个IP 15GiByte的带宽使用,以反映或躲避带宽使用攻击,也许是针对ISP的计量带宽配额。可以通过以下方式实现:

首先为IPv4和IPv6创建IP集:

ipset create IP_QUOTA_SET_OUT hash:ip timeout 345600 counters
ipset create IP_QUOTA_SET_OUT_INET6 hash:ip timeout 345600 counters family inet6

现在添加您的iptables规则。如果尚不存在,则第一行会将IP添加到集合中。如果为该组IP传输的字节数大于指定的数量,则第二行将不匹配。然后对IPv6进行相同的操作。

iptables -I OUTPUT -m set ! --match-set IP_QUOTA_SET_OUT dst -j SET --add-set IP_QUOTA_SET_OUT dst --timeout 345600
iptables -I OUTPUT -m set --match-set IP_QUOTA_SET_OUT dst --bytes-gt 16106127360 -j DROP

ip6tables -I OUTPUT -m set ! --match-set IP_QUOTA_SET_OUT_INET6 src -j SET --add-set IP_QUOTA_SET_OUT_INET6 src --timeout 345600
ip6tables -I OUTPUT -m set --match-set IP_QUOTA_SET_OUT_INET6 src --bytes-gt 16106127360 -j DROP

这将防止攻击,例如用户长时间从您的Web服务器请求大文件,或与此相关的任何服务。对于INPUT链也可以这样做。


0

我所做的主要是因为我对更精致的解决方案不了解,所以每4小时手动检查一次我的Nginx日志,每2分钟检查一次邮件服务器的日志,以检查单个IP的访问量是否过多。我一起运行了一些脚本:

  1. 选中access.log并列出按服务器点击次数排序的前10个IP
  2. 将结果转储到日志文件中
  3. 让另一个脚本查看该日志文件,并禁止在过去X个小时内访问服务器超过X次的任何IP
  4. 保存我的 iptables.save

看起来是这样的:

autoBanIPs_mail.sh
#!/bin/bash

# This script checks the last 2 minutes of log entries to see if any 
# IP has made over 99 connections

now=$(date +"%m_%d_%Y")

/root/bin/checkBadIPs_mail.sh > /home/ipChecker/ipcheckMAIL_$now.txt
cat /home/ipChecker/ipcheckMAIL_$now.txt | \
    grep " \\(\\([9][9]\\)\\|\\([0-9][0-9][0-9]\\+\\)\\) " | \
    awk '{print $2}' > /home/ipChecker/badMailIPs_$now.sh
sed -i "s/^/\/usr\/local\/sbin\/blockIP /g" /home/ipChecker/badMailIPs_$now.sh
/bin/bash /home/ipChecker/badMailIPs_$now.sh
cat /home/ipChecker/ipcheckMAIL_$now.txt >> /home/ipChecker/ipcheckMAIL_$now.log
rm /home/ipChecker/ipcheckMAIL_$now.txt
rm /home/ipChecker/badMailIPs_$now.sh
checkBadIPs_mail.sh

这里要特别注意的一件事是,您需要设置白名单,否则您将开始阻止来自服务器的大量真实IP,而这些服务器只是从中收到大量电子邮件,或者在其他日志的情况下,IP是出于正当原因,对您的服务器造成了很大的影响。我的白名单只是通过在|之后添加grep管道而内置到此脚本中的 grep']' | 看起来像这样的“ grep -v 127.0 |”
您需要花时间教您的服务器哪些高流量IP是合法的,哪些不是。对我而言,这意味着我必须花大约第一周的时间每隔几个小时手动检查一次我的日志,在iplocation.net上查找流量较高的ip,然后添加诸如Amazon,box.com甚至我的家庭/办公室之类的合法文件IP属于此白名单。如果不这样做,则很可能会阻止您使用自己的服务器,或者您将开始阻止合法的邮件/ Web服务器,并导致电子邮件或流量中断。

cat /var/log/mail.log | awk \
    -v d1="$(date --date="-2 min" "+%b %_d %H:%M")" \
    -v d2="$(date "+%b %_d %H:%M")" \
    '$0 > d1 && $0 < d2 || $0 ~ d2' | \
    grep '\[' | grep '\]' | \
    grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | grep -v 127.0 | \
    awk '{print $1}' | sort | uniq -c | sort -n | tail -10
块IP
#!/bin/bash
sudo iptables -I INPUT -s $1 -j DROP
sudo bash -c "iptables-save > /etc/network/iptables.save"

再一次,我知道这简直是地狱,可能有一个很好的干净有效的协议可以完成所有这些工作,但我对此一无所知,这件事已经进行了一年或两年,并阻止了坏人。我非常推荐的一件事是,您可以使用代理或其他服务器来访问主服务器。原因是,如果您一天都在进行Web开发,那在5个小时内对您的自我执行ping操作2000次,以进行某些测试,除了代理服务器,您可能无法进入,就被封锁了。

您可以看到,在checkBadIPs.sh我放置grep -v 127.0的过程中,在我的实际文件中,我对自己的IP和其他受信任的IP范围有很多忽略规则,但是有时您的IP更改了,您忘记了更新,然后就被锁定了在您自己的服务器之外。

无论如何,希望能有所帮助。

更新

我做了一些更改,因此现在不用每隔几个小时检查一次,而是每2分钟检查一次一些日志,主要是ssh auth日志和邮件日志,因为它们受到了很大的打击:(。

我为每个日志文件设置了特定的脚本,尽管从想要检查日志时使用的手动脚本可以很容易地做到这一点。看起来像这样:

#!/bin/bash

log=$1 time=$2

cat /var/log/${log} | awk \
    -v d1="$(date --date="-${time} min" "+%b %_d %H:%M")" \
    -v d2="$(date "+%b %_d %H:%M")" \
    '$0 > d1 && $0 < d2 || $0 ~ d2' | \
    grep '\[' | grep '\]' | \
    grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | \
    sort | uniq -c | sort -n | tail -10

在运行时,这需要2个输入,要扫描的日志文件以及要扫描的历史距离。

因此,如果我想检查mail.log以获取IP计数,比如说过去75分钟,我将运行:

$ sudo script.sh mail.log 75


1
真好!我会使用ipset而不是延长iptables链,但是这个主意很棒,我想我会将它们应用于我的生产服务器。感谢分享!
pepoluan 2014年

2
前几天我只是第一次阅读有关ipset的信息,并高兴地了解它的功能。我有点害怕实现它,只是因为我可能会在一开始就将其破坏并关闭服务器但这是我需要学习的东西。话虽这么说,我的iptable链大概有30-40项,每天或两天只获得1条新链,所以我一点也不担心。
2014年

您是否考虑过fail2ban?
小鸡

0

我同意有关ipsets和tcp标志的评论,但是仍然缺少很多内容:

将xtables-addons geoip匹配而不是ipset用于国家/地区列表。定期更新geoip数据(每月至少一次)。数据比即发即弃的ipset列表更加动态。

考虑使用tcp标志进行连接状态跟踪。例如,tcp RST或ACK仅对已建立的连接有意义。SYN仅对新的和相关的连接有意义。对于已建立的连接,SYN意味着您的SYN + ACK丢失或黑客尝试,应重置,因为连接的双方均不同意声明。

尽管SYN + RST和FIN + RST都不是非法组合,但是SYN + FIN现在在TCP快速打开(TCP选项34)下有效,尤其是对于DNS。即使具有快速打开的SYN数据包也不应分段。我不认为带有PSH和URG标志的规则有用。不要将连接跟踪状态与TCP状态混淆:建立对SYN数据包的RST响应是为了进行跟踪。

SYNPROXY用于转发数据包,对于超出syncookie支持范围的本地传送数据包不添加任何内容。

ICMP错误数据包将始终处于相关状态,并且长度为48:576(如果有效)。IPv6的长度为84:1280。所有其他都应该忽略。由于它们的最大大小也是最小MTU,因此永远不要将它们分割成碎片。ICMP请求(ping,时间戳等)将始终是新的,并且已建立回复。在其他状态下丢弃ICMP数据包。

像带有最新列表且仅接受后续SYN数据包的SSH示例一样,对SMTP也应这样做,这与仅在IP地址数据上进行“灰名单”相似。

在过滤器表中,输入和输出链中的第一个(或第二个,如果先接受已建立的状态数据包)规则应接受回送接口上的所有内容。您应该信任自己的内部数据包。如果不能,那么您将面临防火墙解决方案之外的更大问题。

最后,除非您真的了解规则,否则不要盲目复制规则。如此多的类似规则列表可以做到这一点,并且在大多数情况下,结果是可笑的。


-2
#!/bin/bash
# The following iptables/ip6tables configurations have
# been kindly shared with us from ArckWiki. There are
# a few additions apart from what has been defined.
#
#=================Flush current definitions==============
    iptables -F
    ip6tables -F
    iptables -X
    ip6tables -X

#
#=================Chains=================================
#
#----Define chains for opened ports
    iptables -N TCP
    ip6tables -N TCP
    iptables -N UDP
    ip6tables -N UDP

#
#----Setting up the filter table for NAT
#   iptables -N fw-interfaces
#   ip6tables -N fw-interfaces
#   iptables -N fw-open
#   ip6tables -N fw-open

#
#================Default Chain reactions=================
#
#----Default FORWARD reaction
    iptables -P FORWARD DROP
    ip6tables -P FORWARD DROP

#
#----Default OUTPUT reaction
    iptables -P OUTPUT ACCEPT
    ip6tables -P OUTPUT ACCEPT

#
#----Shellshock
    iptables -A INPUT -m string --algo bm --hex-string '|28 29 20 7B|' -j DROP
    ip6tables -A INPUT -m string --algo bm --hex-string '|28 29 20 7B|' -j DROP

#
#----Default INPUT reaction
    iptables -P INPUT DROP
    ip6tables -P INPUT DROP
#
#----Drop spoofing packets
    iptables -A INPUT -i eth0 -s 127.0.0.0/8 -j DROP
    iptables -A INPUT -i wlan0 -s 127.0.0.0/8 -j DROP
    iptables -A INPUT -i wlan1 -s 127.0.0.0/8 -j DROP
    iptables -A INPUT -s 10.0.0.0/8 -j DROP
    iptables -A INPUT -s 169.254.0.0/16 -j DROP
    iptables -A INPUT -s 172.16.0.0/12 -j DROP
    iptables -A INPUT -s 224.0.0.0/4 -j DROP
    iptables -A INPUT -d 224.0.0.0/4 -j DROP
    iptables -A INPUT -s 240.0.0.0/5 -j DROP
    iptables -A INPUT -d 240.0.0.0/5 -j DROP
    iptables -A INPUT -s 0.0.0.0/8 -j DROP
    iptables -A INPUT -d 0.0.0.0/8 -j DROP
    iptables -A INPUT -d 239.255.255.0/24 -j DROP
    iptables -A INPUT -d 255.255.255.255 -j DROP

#
#================Ping rate limiting globally=============
    iptables -A INPUT -p icmp --icmp-type 8 -m limit --limit 30/min --limit-burst 8 -j ACCEPT
    ip6tables -A INPUT -p icmpv6 --icmpv6-type 8 --match limit --limit-burst 8 -j ACCEPT
    iptables -A INPUT -p icmp --icmp-type 8 -j DROP
    ip6tables -A INPUT -p icmpv6 --icmpv6-type 8 -j DROP

#
#----flooding RST packets, smurf attack Rejection
    iptables -A INPUT -p tcp -m tcp --tcp-flags RST RST -m limit --limit 2/second --limit-burst 2 -j ACCEPT
    ip6tables -A INPUT -p tcp -m tcp --tcp-flags RST RST -m limit --limit 2/second --limit-burst 2 -j ACCEPT

#
#----Bogus packet DROP
    iptables -A INPUT -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
    ip6tables -A INPUT -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
    iptables -A INPUT -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP
    ip6tables -A INPUT -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP

#
#================RELATED,ESTABLISHED reaction============
    iptables -A INPUT --match conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    ip6tables -A INPUT --match conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

#
#================unfetered loopback======================
    iptables -A INPUT -i lo -j ACCEPT
    ip6tables -A INPUT -i lo -j ACCEPT

#
#================INVALID catagory of packets=============
    iptables -A INPUT -p 41 -j ACCEPT
    iptables -A INPUT --match conntrack --ctstate INVALID -j DROP
    ip6tables -A INPUT --match conntrack --ctstate INVALID -j DROP

#
#================IPv6 reactions and definitions==========
    ip6tables -A INPUT -s fe80::/10 -p icmpv6 -j ACCEPT
    ip6tables -t raw -A PREROUTING -p icmpv6 -s fe80::/10 -j ACCEPT
    ip6tables -t raw -A PREROUTING --match rpfilter -j ACCEPT
    ip6tables -t raw -A PREROUTING -j DROP
#
#=======Acceptable INVALIDs and a curteous response======
    iptables -A INPUT -p udp --match conntrack --ctstate NEW -j UDP
    ip6tables -A INPUT -p udp --match conntrack --ctstate NEW -j UDP
    iptables -A INPUT -p tcp --syn --match conntrack --ctstate NEW -j TCP
    ip6tables -A INPUT -p tcp --syn --match conntrack --ctstate NEW -j TCP

#
#================Defining the TCP and UDP chains
#
#########################################################
#            Notes for port open definitions            #
# It is important to note that this should be config-   #
# ured differently if you're providing any routing      #
# activity for any purpose. it is up to you to actively #
# define what suites your needs to get the job done.    #
# In this example, I'm exempting IPv6 from being able   #
# to interact with SSH protocols for two reasons. The   #
# first is because it is generally easier and more com- #
# for internal networks to be deployed with IPv4. The   #
# second reason is, IPv6 can be deployed globally.      #
#########################################################
#
#----SSH configured for eth0
    iptables -A TCP -i eth0 -p tcp --dport ssh -j ACCEPT

#!---Blocking SSH interactions in IPv6
    ip6tables -A TCP -p tcp --dport ssh -j DROP

#!---Leave commented for end service device
#   iptables -A TCP -p tcp --dport 80 -j ACCEPT
#   ip6tables -A TCP -p tcp --dport 80 -j ACCEPT
#   iptables -A TCP -p tcp --dport 443 -j ACCEPT
#   ip6tables -A TCP -p tcp --dport 443 -j ACCEPT
#
#!---Uncomment for remote service to this device
#   iptables -A TCP -p tcp --dport 22 -j ACCEPT
#   ip6tables -A TCP -p tcp --dport 22 -j ACCEPT
#
#!---Uncomment if you're providing routing services
#   iptables -A UDP -p udp 53 -j ACCEPT
#   ip6tables -A UDP -p udp 53 -j ACCEPT
#
#=================Tricking port scanners=================
#
#----SYN scans
    iptables -I TCP -p tcp --match recent --update --seconds 60 --name TCP-PORTSCAN -j DROP
    ip6tables -I TCP -p tcp --match recent --update --seconds 60 --name TCP-PORTSCAN -j DROP
    iptables -A INPUT -p tcp --match recent --set --name TCP-PORTSCAN -j DROP
    ip6tables -A INPUT -p tcp --match recent --set --name TCP-PORTSCAN -j DROP

#
#----UDP scans
    iptables -I UDP -p udp --match recent --update --seconds 60 --name UDP-PORTSCAN -j DROP
    ip6tables -I UDP -p udp --match recent --update --seconds 60 --name UDP-PORTSCAN -j DROP
    iptables -A INPUT -p udp --match recent --set --name UDP-PORTSCAN -j DROP
    ip6tables -A INPUT -p udp --match recent --set --name UDP-PORTSCAN -j DROP

#
#----For SMURF attack protection
    iptables -A INPUT -p icmp -m icmp --icmp-type address-mask-request -j DROP
    iptables -A INPUT -p icmp -m icmp --icmp-type timestamp-request -j DROP
    iptables -A INPUT -p icmp -m limit --limit 2/second --limit-burst 2 -j ACCEPT
    ip6tables -A INPUT -p icmpv6 -m limit --limit 2/second --limit-burst 2 -j ACCEPT

#
#----Ending all other undefined connections
    iptables -A INPUT -j DROP
    ip6tables -A INPUT -j DROP

#
#=======Defining the IN_SSH chain for bruteforce of SSH==
#
#!---I've elected to keep IPv6 out of this realm for
#!---ease of use
    iptables -N IN_SSH
    iptables -A INPUT -p tcp --dport ssh --match conntrack --ctstate NEW -j IN_SSH
    iptables -A IN_SSH --match recent --name sshbf --rttl --rcheck --hitcount 3 --seconds 10 -j DROP
    iptables -A IN_SSH --match recent --name sshbf --rttl --rcheck --hitcount 4 --seconds 1800 -j DROP
    iptables -A IN_SSH --match recent --name sshbf --set -j ACCEPT
    iptables -A INPUT -p tcp --dport ssh -m conntrack --ctstate NEW -j IN_SSH

#
#==================Setting up a NAT gateway==============
#
#########################################################
#                                                       #
# I commented this half out because it's not something  #
# that will apply to all setups. Make note of all par-  #
# tinate interfaces and what exactly is going on.       #
#                                                       #
#########################################################
#
#----Setting up the FORWARD chain
#   iptables -A FORWARD --match conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
#   ip6tables -A FORWARD --match conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
#
#
#----Defining the fw-interfaces/open chains for FORWARD
#   iptables -A FORWARD -j fw-interfaces
#   ip6tables -A FORWARD -j fw-interfaces
#   iptables -A FORWARD -j fw-open
#   ip6tables -A FORWARD -j fw-open
#   iptables -A FORWARD -j DROP # Should be REJECT. But, fuck them
#   ip6tables -A FORWARD -j DROP
#   iptables -P FORWARD DROP
#   ip6tables -P FORWARD DROP
#
#
#----Setting up the nat table
#   iptables -A fw-interfaces -i ### -j ACCEPT
#   ip6tables -A fw-interfaces -i ### -j ACCEPT
#   iptables -t nat -A POSTROUTING -s w.x.y.z/S -o ppp0 -j MASQUERADE
#   ip6tables -t nat -A POSTROUTING -s fe::/10 -o ppp0 -j MASQUERADE
#----The above lines should be repeated specifically for EACH interface
#
#----Setting up the PREROUTING chain
#
#######################################################
#                             #
# The PREROUTING chain will redirect either port      #
# targets to be redirected. This can also redirect    #
# traffic inbound to your network from the gateway    #
# to this machine. This can be useful if you're using #
# a honeypot or have any service within your network  #
# that you want to be pointed to a specific device.   #
#                             #
#######################################################
#
#----SSH honeypot server
#   iptables -A fw-open -d HONEYPOT_IP -p tcp --dport 22 -j ACCEPT
#   ip6tables -A fw-open -d HONEYPOT_IP -p tcp --dport 22 -j ACCEPT
#----With intuition, you can configure the above to also direct specific
#----requests to other devices providing those services. The bellow will
#----be for a squid server
#   iptables -A fw-open -d SQUID_IP -p tcp --dport 80 -j ACCEPT
#   ip6tables -A fw-open -d SQUID_IP -p tcp --dport 80 -j ACCEPT
#   iptables -t nat -A PREROUTING -i ppp0 -p tcp --dport 8000 -j DNAT --to SQUID_IP
#   ip6tables -t nat -A PREROUTING -i ppp0 -p tcp --dport 8000 -j DNAT --to SQUID_IP
#
#===============Declare configurations=================
    iptables -nvL
    ip6tables -nvL

1
尽管大喊大叫,但我无法理解您的帖子信息。
迪尔·亨特
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.