iptables
安全技术和防火墙
安全技术
- 入侵检测系统
- 入侵防御系统
- 防火墙
防水墙
广泛意义上的防水墙:防水墙(Waterwall),与防火墙相对,是一种防止内部信息泄漏的安全产品。网络、外设接口、存储介质和打印机构成信息泄漏的全部途径。防水墙针对这四种泄密途径,在事前、事中、事后进行全面防护。其与防病毒产品、外部安全产品一起构成完整的网络安全体系。
防火墙的分类
按保护范围分类:
- 主机防火墙:服务范围为当前一台主机
- 网络防火墙:服务范围为防火墙一侧的局域网
按实现方式划分:
- 硬件防火墙
- 软件防火墙
按网络协议划分:
- 网络层防火墙:OSI 模型下四层,又称为包过滤防火墙
- 应用层防火墙/代理服务器:代理网关,OSI 模型七层
现实生产环境中所使用的防火墙一般都是二者结合体,即先检查网络数据,通过之后再送到应用层去检查
Linux 防火墙的基本认识
Linux 防火墙是由Netfilter组件提供的,Netfilter 工作在内核空间,集成在 linux 内核中
Netfilter 是 Linux 2.4.x 之后新一代的 Linux 防火墙机制,是 linux 内核的一个子系统。Netfilter 采用模块化设计,具有良好的可扩充性,提供扩展各种网络服务的结构化底层框架。Netfilter 与 IP 协议栈是无缝契合,并允许对数据报进行过滤、地址转换、处理等操作
1 | [root@centos8 ~]$grep -m 10 NETFILTER /boot/config-4.18.0-193.el8.x86_64 |
防火墙工具介绍
iptables:工作在用户空间,用来编写规则,写好的规则被送往 netfilter,告诉内核如何去处理包
firewalld:CentOS7 引入
nftables:CentOS 8 新特性,2013 年末合并到 Linux 内核中,自 2014 年以来已在内核 3.13 中可用。
它重用了 netfilter 框架的许多部分,例如连接跟踪和 NAT 功能。它还保留了命名法和基本 iptables 设计
的几个部分,例如表,链和规则。就像 iptables 一样,表充当链的容器,并且链包含单独的规则,这些
规则可以执行操作,例如丢弃数据包,移至下一个规则或跳至新链。从用户的角度来看,nftables 添加了一个名为 nft 的新工具,该工具替代了 iptables,arptables 和
ebtables 中的所有其他工具。从体系结构的角度来看,它还替换了内核中处理数据包过滤规则集运行时
评估的那些部分。总之:nftables 应该是未来的主流,现在 iptables 还是要重点学习,firewalld 了解即可
netfilter 中五个勾子函数(hook)
netfilter 在内核的五个位置放了钩子函数(hook):
1 | INPUT、OUTPUT、FORWARD、PREROUTING、POSTROUTING |
提示:从 Linux kernel 4.2 版以后,Netfilter 在 prerouting 前加了一个 ingress 勾子函数。可以使用这个新的入口挂钩来过滤来自第 2 层的流量,这个新挂钩比预路由要早,基本上是 tc 命令(流量控制工具)的替代品
iptables 的组成
iptables 由五张 表(table) 组成:
- filter 表:过滤规则表,根据预定义的规则过滤符合条件的数据包,默认表
- nat 表:network address translation 地址转换规则表;修改数据包中的源、目标 iP 和端口
- mangle:修改数据标记位规则表
- raw:关闭启用的连接跟踪机制,加快封包穿越防火墙速度
- security:用于强制访问控制(MAC)网络规则,由 Linux 安全模块(如 SELinux)实现
五张表的优先级:security –>raw–>mangle–>nat–>filter,我们重点研究后面四张表
每张表由若干功能类似的 链(chain)组成,每条链上有若干类似的 规则(rule)
表不能自定义,链可以自定义,但是 iptables 也内置了 5 种链,与 5 个钩子函数同名,内置链上每条过滤规则都调用与链同名的钩子函数。
1 | INPUT、OUTPUT、FORWARD、PREROUTING、POSTROUTING |
注意:自定义的链不能直接添加到表中,只能作为 target 添加到内置链上,间接的实现添加到表中
内核中数据的传输流程
在每个 hook 放置若干表,按照表的优先级,依次执行表内的同名链上的规则,例如 INPUT 钩子函数会依次执行 mangle、nat、filter 表中的 INPUT 链上的规则。
标注:红色的表示钩子函数或者内置链,黄色的表示 table
显然,内置链和内置表的关系:
netfilter 完整流程
iptables
mysql:数据库中有表,表中有一条条的数据
iptables:表中有链,链上有一条条的规则
规则 rule
规则由 匹配条件 和 处理动作组成,规则在链上的顺序即其检查时生效的顺序
匹配条件
- 基本匹配:IP,端口,TCP 的 Flags(SYN,ACK 等)
- 扩展匹配:调用 netfilter 中的模块,实现各种复杂匹配
处理动作
处理动作称为 target,跳转目标,分为两种:内建的处理动作 和 自定义链。
常用的内建处理动作:
ACCEPT:允许数据包通过
DROP:直接丢弃数据包,不给任何回应信息,这时候客户端会感觉自己的请求泥牛入海了,过了超时时间才会有反应
REJECT:拒绝数据包通过,必要时会给数据发送端一个响应的信息,客户端刚请求就会收到拒绝的信息
SNAT:源地址转换,解决内网用户用同一个公网地址上网的问题
MASQUERADE:是 SNAT 的一种特殊形式,适用于动态的、临时会变的 ip 上
DNAT:目标地址转换
REDIRECT:在本机做端口映射
LOG:非中断 target,本身不拒绝和允许,放在拒绝和允许规则前,并将日志记在/var/log/messages 系统日志中
- –log-level level 级别: debug、info、notice、warning、error、crit、alert、emerg
- –log-prefix prefix 日志前缀,用于区别不同的日志,最多 29 个字符
iptables 添加规则使要考虑
- 要实现哪种功能:判断添加在哪张表上
- 报文流经的路径:判断添加在哪条链上
- 报文的流向:判断源和目的
- 匹配规则:业务需要
iptables 命令用法
1 | iptables [-t table] {-A|-C|-D} chain rule-specification |
-t:指定表,默认 filter 表
-A:以 append 的方式添加 rule,iptables 添加 rule 后会立马生效
-I:以 insert 的方式添加 rule
-C:检查 rule 是否存在
-D :删除 rule,可以通过 指明规则序号 或 指明规则本身 两种方式
-R:replace,替换指定链上的指定规则编号
-S:打印指定链上的所有 rule,不指定链则打印表中所有 rule
-L:list, 列出指定链上的所有规则,不指定链则列出表中所有 rule
-F:flush,清空指定的链
-Z:zero,置零。每条 rule 都有两个计数器
- 匹配到的报文数
- 匹配到的所有报文的大小之和
-N:new, 自定义一条新的链
-X:delete,删除自定义的空的链
-P:Policy,设置默认策略;对 filter 表中的链而言,其默认策略有:ACCEPT:接受, DROP:丢弃
-E:重命名自定义链,引用计数不为 0 的自定义链不能够被重命名,也不能被删除
参数:
- -m:match
- -j:jump target
其他选项:
- -v:verbose,显示更详细的信息
- -n:numeric,数字输出。IP 地址和端口会以数字的形式打印
- -w:
- -W:
- -x:扩展数字。显示包和字节计数器的精确值,代替用 K,M,G 表示的约数。 这个选项仅能用于 -L 命令。
--line-numbers
:当列表显示规则时,在每个规则的前面加上行号,与该规则在链中的位置相对应,这个常用- –modprobe=command:
iptables 基本匹配条件
注意:当一条规则中有多个匹配条件时,这多个匹配条件之间,默认存在”与”的关系。也就是说当一条规则中存在多个匹配条件时,报文必须同时满足这些条件,才算做被规则匹配
无需加载模块,由 iptables/netfilter 自行提供,! 是取反的意思
基本匹配条件 | 说明 |
---|---|
[!] -s address[/mask][,…] | 源地址 |
[!] -d address[/mask][,…] | 目标地址 |
[!] -p protocol | 指定协议,tcp、udp、icmp 等,可以指定哪些协议参考/etc/protocols, 还可以使用数字 0,相当于 all,匹配所有协议 |
[!] -i inter_name | in interface,报文流入的接口;只能应用于数据报文流入环节, 只应用于 INPUT、FORWARD、PREROUTING 链 |
[!] -o inter_name | out interface,报文流出的接口;只能应用于数据报文流出的环节, 只应用于 FORWARD、OUTPUT、POSTROUTING 链 |
范例:
1 | # 添加规则,并指定规则号:禁止10.0.0.6的ping请求 |
iptables 扩展匹配条件
需要加载扩展模块(/usr/lib64/xtables/*)方可生效,扩展模块可以使用 man 命令查看,扩展匹配条件分为 隐式扩展 和 显式扩展
隐式扩展
iptables 在使用 -p 指定了特定协议时,可以省略协议同名扩展,直接写扩展匹配条件即可,这类扩展就是隐式扩展,例如 tcp、udp、icmp
tcp 扩展模块 匹配条件
[!] –sport port[:port]:匹配 tcp 报文的源端口或端口范围
1
2# 范例:
iptables -t filter -I OUTPUT -d 192.168.1.146 -p tcp -m tcp --sport 22:25 -j REJECT[!] –dport port[:port]:匹配 tcp 报文的目标端口或端口范围
1
2# 范例
iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m tcp --dport 22:25 -j REJECT[!] –tcp-flags mask comp:
- mask: 需检查的标志位列表,用,分隔 , 例如 SYN,ACK,FIN,RST
- comp:在 mask 列表中必须为 1 的标志位列表,无指定则必须为 0,用,分隔 tcp 协议的扩展选项
1
2
3
4
5# 范例:
# 要检查的标志位为SYN,ACK,FIN,RST四个,其中SYN必须为1,余下的必须为0,第一次握手
--tcp-flags SYN,ACK,FIN,RST SYN
# 以上写法可以简写
--syn
udp 扩展模块 匹配条件
- [!] –sport port[:port]:匹配报文的源端口或端口范围
- [!] –dport port[:port]:匹配报文的目标端口或端口范围
icmp 扩展模块 匹配条件
- [!] –icmp-type {type[/code]|typename}:
- type/code
- 0/0 echo-reply icmp 应答
- 8/0 echo-request icmp 请求
- type/code
1 | # 范例:不允许其他人ping我,而我可以ping其他人 |
显式扩展
必须使用-m 指定使用的扩展,下面是常用的显式扩展:
multiport 扩展 匹配条件
以离散方式定义多端口匹配,最多指定 15 个端口
- [!] –sports port[,port|,port:port]…:指定多个源端口
- [!] –dports port[,port|,port:port]…:指定多个目标端口
- [!] –ports port[,port|,port:port]…:指定多个源或目标端口
iprange 扩展 匹配条件
指明连续的(但一般不是整个网络)ip 地址范围
- [!] –src-range from[-to] 源 IP 地址范围
- [!] –dst-range from[-to] 目标 IP 地址范围
1 | # 范例 |
mac 扩展 匹配条件
指定源 MAC 地址,,适用于:PREROUTING, FORWARD,INPUT chains
注意不能指定目标 MAC 地址,因为无法指定,也没有意义
- [!] –mac-source XX:XX:XX:XX:XX:XX
string 扩展 匹配条件
对报文中的应用层数据做字符串模式匹配检测
- –algo {bm|kmp}:字符串匹配算法
- –from offset:开始偏移
- –to offset:结束偏移
- [!] –string pattern:模式匹配要检测的字符串
- [!] –hex-string pattern:模式匹配要检测的字符串,16 进制格式
1 | # 范例 |
time 扩展 匹配条件
注意:CentOS 8 此模块有问题
根据将报文到达的时间与指定的时间范围进行匹配
- –datestart YYYY[-MM[-DD[Thh[:mm[:ss]]]]] 日期
- –datestop YYYY[-MM[-DD[Thh[:mm[:ss]]]]]
- –timestart hh:mm[:ss] 时间
- –timestop hh:mm[:ss]
- [!] –monthdays day[,day…] 每个月的几号
- [!] –weekdays day[,day…] 星期几,1 – 7 分别表示星期一到星期日
- –kerneltz:内核时区(当地时间),非常不建议使用
connlimit 扩展 匹配条件
对每 IP 所能够发起并发连接数做限制;可防止 Dos(Denial of Service,拒绝服务)攻击
- –connlimit-upto N:连接的数量小于等于 N 时匹配
- –connlimit-above N:连接的数量大于 N 时匹配
limit 扩展 匹配条件
”令牌桶“算法,对 报文到达速率 进行限制,即限制单位时间内流入的包的数量
–limit-burst N:前 N 个包不限制,
–limit N[/second|/minute|/hour|/day]:单位时间内通过 N 个包
1 | # 范例:下面两条规则配合使用,限制每分钟ping10次,即每6秒ping一次 |
state 扩展 匹配条件
state 直译为 状态,state 模块可以让 iptables 实现”连接追踪“机制,英文名是 conntrack 机制。
简单说就是追踪本机的请求和相应之间的状态。
state 扩展实现“连接追踪”需要依赖 nf_conntrack_ipv4 等内核模块,可以通过 modprobe 命令手动把所需内核模块加载到内存中,但实际上没有这个必要,因为 iptables 会自动加载所需内核模块
state 模块有 5 中状态:NEW、ESTABLISHED、RELATED、INVALID、UNTRACKED
- NEW:新发出请求;只要连接追踪信息库(/proc/net/nf_conntrack)中不存在此连接的相关信息条目,就识别为第一次发出的请求
- ESTABLISHED:NEW 状态之后,连接追踪信息库中为其建立的条目失效之前期间内所进行的通信状态
- RELATED:新发起的但与已有连接相关联的连接,如:ftp 协议中的数据连接与命令连接之间的关系
- INVALID:无效的连接,如 flag 标记不正确
- UNTRACKED:未进行追踪的连接,如:raw 表中关闭追踪
注意:state 模块的状态和 TCP 的状态没有关系,对于 state 模块而言,只要两台机器在”你来我往”的通信,就算建立起了连接。所以在 TCP/IP 协议中,UDP 和 ICMP 是没有连接状态的,而在 state 模块中,所有的协议都是有连接状态的
查看连接追踪信息库:
1 | [root@centos8 ~]$cat /proc/net/nf_conntrack |
调整连接追踪功能所能够容纳的最大连接数量:
1 | # 使用sysctl修改 |
查看目前连接跟踪有多少条目:
1 | [root@4710419222 ~]$cat /proc/sys/net/netfilter/nf_conntrack_count |
不同的协议的连接追踪时长:
1 | [root@4710419222 ~]$ll /proc/sys/net/netfilter/ | grep timeout |
说明:
- 当服务器连接多于最大连接数时,报错 :
kernel: ip_conntrack: table full, dropping packet
,并且导致建立 TCP 连接很慢 - 各种状态超时后,链接会从表中删除
连接过多的解决方法有两个:
加大 nf_conntrack_max 值
1
2
3vi /etc/sysctl.conf
net.nf_conntrack_max = 393216
net.netfilter.nf_conntrack_max = 393216降低 tcp 各种状态的超时时间
1
2
3
4
5
6
7vi /etc/sysctl.conf
net.netfilter.nf_conntrack_tcp_timeout_established = 300
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 120
iptables -t nat -nvL
格式
1 | [!] --state state,state... |
范例:不允许 10.0.0.79 访问本机,但是本机能访问 10.0.0.79
1 | [root@centos8 ~]$iptables -t filter -A INPUT -m state --state ESTABLISHED -j ACCEPT |
rule 优化
安全放行所有入站和出站的状态为 ESTABLISHED 状态连接,建议放在第一条,效率更高
谨慎放行入站的新请求
有特殊目的限制访问功能,要在放行规则之前加以拒绝
同类规则(访问同一应用,比如:http ),匹配范围小的放在前面,用于特殊处理
不同类的规则(访问不同应用,一个是 http,另一个是 mysql ),匹配范围大的放在前面,效率更高
1 | -s 10.0.0.6 -p tcp --dport 3306 -j REJECT |
应该将那些可由一条规则能够描述的多个规则合并为一条,减少规则数量,提高检查效率
设置默认策略,建议白名单(只放行特定连接)
iptables -P,不建议,容易出现“自杀现象”
规则的最后定义规则做为默认策略,推荐使用,放在最后一条
rule 保存
使用 iptables 命令定义的规则,,其生效期限为 kernel 存活期限,即重启失效
持久保存规则:
1 | # CentOS6 将规则覆盖保存至/etc/sysconfig/iptables文件中 |
加载规则:
CentOS6 自动从/etc/sysconfig/iptables 重新载入规则
1 | service iptables restart |
CentOS7、8
1 | iptables-restore < file |
- -n:noflush,清除原有规则
- -t:–test,仅分析生成规则集,但不提交
开机自动重载规则
CentOS6 只要设置 iptables 开机自启,然后关机前使用保存规则即可
1 | chkconfig iptables on |
CentOS7、8 有两种方式
方法一:将自动载入规则的命令写入开机自启脚本/etc/rc.d/rc.local 文件
1 | # 将自动载入规则的命令写入开机自启脚本/etc/rc.d/rc.local文件 |
方法二:使用 iptables-services
1 | # 安装软件 |
网络防火墙
FORWARD
利用 filter 表的 FORWARD 链,可以充当网络防火墙
- 请求 - 响应报文均会经由 FORWARD 链,要注意规则的方向性
- 如果要启用 conntrack 机制,建议将双方状态为 ESTABLISHED 的报文直接放行
[实验:FORWARD 链实现内外网络的流量控制](16.1 实验 FORWARD 链实现内外网络的流量控制.md)
NAT
客户机和服务器都在局域网中,躲在防火墙后面,通过路由器连接网络。
NAT 是地址转换表,表中规则的常用 target:
- SNAT:负责将局域网 IP 转成公网 IP,S 是源地址的意思,适用于固定的公网 IP
- MASQUERADE:相较与 SNAT,MASQUERADE 适用于动态的公网 IP,如:拨号网络
- DNAT:负责将公网 IP 转成局域网 IP,D 是目标地址的意思;
- REDIRECT:
这么说有些抽象,我们看下面的例子:
SNAT
我本机的 IP 是 172.16.135.189/16,对外的公网 IP 是 39.164.140.134,当我访问互联网中的网站时,防火墙负责将 172.16.135.189 转成 39.164.140.134,等返回数据的时候,再把 39.164.140.134 转成 172.16.135.189。
有一个问题,局域网中的 ip 成百上千,大家对外的公网 IP 却都是 39.164.140.134,如果多台主机同时访问同一网站,路由器是如何做到准确的转发消息呢?
答案是对目标 IP 相同的请求分别绑定不同的端口号,例如 PC1 和 PC2 两台主机同时访问网站 http://lujinkai.cn,防火墙会把PC1的IP转成39.164.140.134:1234,把PC2的IP转成39.164.140.134:2345(1234和2345是随便写的,只要两个端口不一样就行)
范例:
1 | iptables -t nat -A POSTROUTING -s 172.16.0.0/16 -j SNAT --to-source 39.164.140.134 |
- –to-source:将报文的源 IP 修改为公网 IP
SNAT 中隐含了另一个技术:PNAT,即自动分配端口,只不过我们不单独说它。
MASQUERADE
如果家里拨号上网,外网 IP 不固定,可以使用 MASQUERADE
范例:
1 | iptables -t nat -A POSTROUTING -s 10.0.1.0/24 -j MASQUERADE |
可以把 MASQUERADE 理解为动态的、自动化的 SNAT,如果没有动态 SNAT 的需求,没有必要使 MASQUERADE,因为 SNAT 更加高效。
DNAT
http://lujinkai.cn 网站的 IP 是 47.105.171.233,这个公网 IP 的后面可能是一台服务器,也可能是服务器集群,总之无论有多少服务器,防火墙外的人看不出来。当我访问去访问网站时,阿里云的防火墙会将 39.164.140.134 转成局域网 IP,然后将请求转发到真实的服务器。
范例:
1 | [root@centos8 ~]$iptables -t nat -A PREROUTING -d 192.168.248.2 -p tcp --dport 80 -j DNAT --to-destination 10.0.0.175:80 |
- –to-destination:将报文的目标地址修改为内网 IP,并指定端口号
REDIRECT
DNAT 可以对 IP 和端口进行映射,REDIRECT 只能应用在本机,对本机的端口进行映射,比如将本机的 80 端口映射到 8080 端口上,当别的机器访问本机的 80 端口时,报文会被重定向到本机的 8080 端口上,此时本机只需要监听 8080 端口,不需要监听 80 端口
1 | iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080 |
- –to-ports:端口转换
REDIRECT 规则只能定义在 PREROUTING 链或者 OUTPUT 链中
firewalld 服务
CentOS6 不支持 firewalld,CentOS8 支持 firewalld,但是官方推荐使用 ntf,所有 firewalld 了解即可。
在 iptables 的基础上,预定义了一些链(zone)和服务,以下以 CentOS7 中的 firewalld 为例:
zone
zone 名称 | 默认配置 |
---|---|
trusted | 允许所有流量 |
home | 拒绝除和传出流量相关的,以及 ssh,mdsn,ipp-client,samba-client,dhcpv6-client 预定义服务之外其它所有传入流量 |
internal | 和 home 相同 |
work | 拒绝除和传出流量相关的,以及 ssh,ipp-client,dhcpv6-client 预定义服务之外的其它所有传入流量 |
public | 拒绝除和传出流量相关的,以及 ssh,dhcpv6-client 预定义服务之外的其它所有传入流量,新加的网卡默认属于 public zone |
external | 拒绝除和传出流量相关的,以及 ssh 预定义服务之外的其它所有传入流量,属于 external zone 的传出 ipv4 流量的源地址将被伪装为传出网卡的地址。 |
dmz | 拒绝除和传出流量相关的,以及 ssh 预定义服务之外的其它所有传入流量 |
block | 拒绝除和传出流量相关的所有传入流量 |
drop | 拒绝除和传出流量相关的所有传入流量(甚至不以 ICMP 错误进行回应) |
firewall-cmd
firewall-cmd 是 firewalld 的命令行工具。
1 | firewall-cmd [OPTIONS...] |
常见选项:
- –get-zones:列出所有可用区域
- –get-default-zone:查询默认区域
- –set-default-zone=
:设置默认区域 - –get-active-zones:列出当前正使用的区域
- –add-source=
[–zone= ]:添加源地址的流量到指定区域,如果无–zone= 选项,使用默认区域 - –remove-source=
[–zone= ]:从指定区域删除源地址的流量,如无–zone= 选项,使用默认区域 - –add-interface=
[–zone= ]:添加来自于指定接口的流量到特定区域,如果无–zone= 选项,使用默认区域 - –change-interface=
[–zone= ]:改变指定接口至新的区域,如果无–zone=选项,使用默认区域 - –add-service=
[–zone= ]:允许服务的流量通过,如果无–zone= 选项,使用默认区域 - –add-port=<PORT/PROTOCOL>[–zone=
]:允许指定端口和协议的流量,如果无–zone= 选项,使用默认区域 - –remove-service=
[–zone= ]:从区域中删除指定服务,禁止该服务流量,如果无–zone= 选项,使用默认区域 - –remove-port=<PORT/PROTOCOL>[–zone=
]:从区域中删除指定端口和协议,禁止该端口的流量,如果无–zone= 选项,使用默认区域 - –reload:删除当前运行时配置,应用加载永久配置
- –list-services:查看开放的服务
- –list-ports:查看开放的端口
- –list-all [–zone=
]:列出指定区域的所有配置信息,包括接口,源地址,端口,服务等,如果无–zone= 选项,使用默认区域
范例:
1 | #查看默认zone |