linux防火墙ufw以及iptables
1,直到服务器被攻击了,才知道防火墙的重要性
问题不大,被攻击了也就是cpu被别人跑满,账号密码被换掉而已。。。所以防火墙还是比较重要的,尤其是公网ip的防火墙
2,ufw
这个是ubuntu入门级别的防火墙了,使用方法比较简单,ubuntu系统自带,
常用指令:
sudo apt-get install ufw #安装ufw sudo ufw status numbered #查看防火墙过滤规则 sudo ufw enable/disable #激活防火墙,开机时自动启动/不启动 sudo ufw delete 3 #删除防火墙的规则 sudo ufw logging low #启用防火墙的日志功能,默认的记录日志等级是low sudo ufw allow from 49.72.93.80 sudo ufw default allow/allow|deny|reject incoming|outgoing #设置默认允许服务器向外访问。 sudo ufw limit in 21116 #限制21115端口的接入访问 限制访问次数6次/30s
log文件在/var/log/ufw.log中,
log等级说明如下:
*low 记录与默认策略冲突的封装数据包(记录速度被限制)。记录与规则符合的数据包(没有要求关闭记录的)
*medium 记录与默认策略冲突的数据包(包括被规则允许的)、无效数据包、所有新连接。记录速度被限制。
*high 同medium,只是没有记录速度限制。附加记录所有数据包(有记录速度限制)。
*full 与high等同,只是取消记录限制。
日志文件位置:/var/log/ufw.log,日志文件内容解析:
[UFW BLOCK]:这是记录事件的描述开始的位置。在此例中,它表示阻止了连接。
IN:如果它包含一个值,那么代表该事件是传入事件
OUT:如果它包含一个值,那么代表事件是传出事件
MAC:目的地和源 MAC 地址的组合
SRC:包源的 IP
DST:包目的地的 IP
LEN:数据包长度
TTL:数据包 TTL,或称为 time to live。 在找到目的地之前,它将在路由器之间跳跃,直到它过期。
PROTO:数据包的协议
SPT:包的源端口
DPT:包的目标端口
WINDOW:发送方可以接收的数据包的大小
SYN URGP:指示是否需要三次握手。 0 表示不需要。
总体而言,简单可读性高,但是,并不算很容易配置,比如,我想限制21110端口的访问速率,改为每秒一次,那我就去改/etc/ufw/user.rule,改了也reload过了,发现根本改不动,得,咱还是换个工具吧。
3.iptables
这是存在于ubuntu内核中的程序,也是厉害了,这么说可能也不是很确切,防火墙是存在于linux内核中的程序,你要改防火墙规则,可以使用iptables或者是nft,我不知道他们具体关系是啥,但是一个比一个更底层,一个比一个更难理解。
说回来iptables是一个管着机器端口的程序,不光是外来访问,本地端口如3306也在它掌控范围,不仅能决定数据包是否能通过,还可以转发和修改数据包的内容,更有甚的icmp(能否ping通),v4还是v6通讯,网卡,docker容器类的虚拟端口等,全能管得到,它还知道你当前连接状态,限制流量等,也是内容非常非常庞杂了,主要参考的教程如下:感谢这位作者,要调试它首先要知道它的工作原理:
它有四张表:
• filter:这里面的链条,规则,可以决定一个数据包是否可以到达目标进程端口
• mangle: 这里面的链条,规则,可以修改数据包的内容,比如ttl
• nat:这里面的链条,规则,可以修改源和目标的ip地址,从而进行包路由。
• raw:这里面的链条,规则,能基于数据包的状态进行规则设定
每个表里都有一些内容,比如,filter表中,有如下规则:规则1,来自某个IP的包,直接拒绝。规则2,你要想访问我的80端口,直接拒绝,,,把规则1和2串联起来,就是一条链,当有一个包到了这张表的时候,它就会按照链的顺序进行匹配,如果规则1 不通过,就直接返回拒绝包的消息,这个包就不会往下走了。如果一直走完没有被拒绝,那就继续走其他的表。如果一直没有被拒绝,那这个包会最终到达它的目的地,返回的结果再经由路由判断一遍,就能完成一次收发了。当然了,实际情况更复杂一些。
细节咱也不多说,就从应用的角度出发,我上哪里去写一个规则,限制某个端口的数据访问,省得别人暴力破解我的密码。
如果你和我一样,要限制别人对本机的访问,大家一半都在filter表中chain:INPUT中做事情。所以话不多说,我们先看看filter中的内容。由于ufw我这边的filter类似这样:
Chain INPUT (policy DROP 25714 packets, 1351K bytes) num pkts bytes target prot opt in out source destination 1 103M 114G ufw-before-logging-input all -- * * 0.0.0.0/0 0.0.0.0/0 2 103M 114G ufw-before-input all -- * * 0.0.0.0/0 0.0.0.0/0 3 5179K 360M ufw-after-input all -- * * 0.0.0.0/0 0.0.0.0/0 4 5179K 360M ufw-after-logging-input all -- * * 0.0.0.0/0 0.0.0.0/0 5 5179K 360M ufw-reject-input all -- * * 0.0.0.0/0 0.0.0.0/0 6 5179K 360M ufw-track-input all -- * * 0.0.0.0/0 0.0.0.0/0 Chain FORWARD (policy DROP 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 DOCKER-USER all -- * * 0.0.0.0/0 0.0.0.0/0 2 0 0 DOCKER-ISOLATION-STAGE-1 all -- * * 0.0.0.0/0 0.0.0.0/0 3 0 0 ACCEPT all -- * docker0 0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED 4 0 0 DOCKER all -- * docker0 0.0.0.0/0 0.0.0.0/0 5 0 0 ACCEPT all -- docker0 !docker0 0.0.0.0/0 0.0.0.0/0 6 0 0 ACCEPT all -- docker0 docker0 0.0.0.0/0 0.0.0.0/0 7 0 0 ufw-before-logging-forward all -- * * 0.0.0.0/0 0.0.0.0/0 8 0 0 ufw-before-forward all -- * * 0.0.0.0/0 0.0.0.0/0 9 0 0 ufw-after-forward all -- * * 0.0.0.0/0 0.0.0.0/0 10 0 0 ufw-after-logging-forward all -- * * 0.0.0.0/0 0.0.0.0/0 11 0 0 ufw-reject-forward all -- * * 0.0.0.0/0 0.0.0.0/0 12 0 0 ufw-track-forward all -- * * 0.0.0.0/0 0.0.0.0/0 Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 94M 106G ufw-before-logging-output all -- * * 0.0.0.0/0 0.0.0.0/0 2 94M 106G ufw-before-output all -- * * 0.0.0.0/0 0.0.0.0/0 3 164K 13M ufw-after-output all -- * * 0.0.0.0/0 0.0.0.0/0 4 164K 13M ufw-after-logging-output all -- * * 0.0.0.0/0 0.0.0.0/0 5 164K 13M ufw-reject-output all -- * * 0.0.0.0/0 0.0.0.0/0 6 164K 13M ufw-track-output all -- * * 0.0.0.0/0 0.0.0.0/0
除了以上内容,还有一堆ufw建立的chain,首先清理一下:
sudo iptables -t filter -nvL --line #指定查看filter表中的所有链和规则 sudo iptables -t filter --line -nvL limit-reject #指定查看filter表中的limit-reject链中的规则
sudo iptables -t filter -D INPUT 1 #删除filter表中input链的第一条规则 sudo iptables -t filter -X ufw-reject-input #删除filter表中一个叫 ufw-reject-input的链,默认的链以及有引用的链不要乱删啊!
我基本把ufw的内容全删了,docker的暂时不动。
接下来定制自己的规则,规则主要包含两部分:条件 以及 动作
条件类似于:来自某个ip的包,指向某个IP的包,指向某个端口的包,等等
动作较简单,规定好的几类如下:
• ACCEPT: 直接接受该数据包,不会再走其他链条和规则。比如filter中的input表中的某个规则命中后,动作是ACCEPT,那么该数据包将被直接送达目标进程端口。
• DROP: 直接抛弃该数据包,并且没有任何返回。且不会再走其他链和规则
• REJECT: 跟DROP类似,但好歹还是会跟请求方返回一些拒绝信息,比如我们拒绝掉ICMP协议后,ping该主机,会返回“destination host unreachable”
• RETURN: 当前规则不做任何处理,返回。让给下一个规则处理
• LOG : 同RETURN类似,但只是会将请求信息记录到系统日志中,记录路径
还要补充一个,动作也可以指向一个自定义的chain,这样做的好处是,chain对规则进行了分组,可读性高而且方便管理
我的需求是,限制某些端口的访问频率,防止别人对我的暴力破解。这是我编辑的内容:
iptables -t filter -I INPUT -i lo -j ACCEPT #首先在filter表的默认的INPUT链中接受所有的本地环回包,这个通常是自己访问自己,问题不大。 sudo iptables -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT #filter表的默认的INPUT链(默认的了哈,后面不说了)把已经建立的连接和由此相关的连接都接受。-I的意思是insert,就是在链前面插入规则,-A的意思是append在链后面插入规则。 iptables -t filter -N limit-reject #在filter表中新增一个链 limit-reject ,这个链主要用处是限速以及速度太快的时候去拒绝访问的,顺带写了一下log sudo iptables -t filter -I limit-reject -p tcp -m multiport --dport 22,3000,21110,21116,21117 -m limit --limit 30/minute --limit-burst 10 -j ACCEPT #编辑filter表,limit-reject链,新增一个限制规则,是,限制对22,3000,21110,21116,21117端口的访问,访问达到10次以后,就每2秒限制一次,原则上因为前面已经有一句已经建立的连接都接受的规则了,这里走到这里的应该都是新的连接请求,符合条件就accept,不符合继续往下走 sudo iptables -t filter -A limit-reject -p tcp -m multiport --dport 22,3000,21110,21116,21117 -m limit --limit 3/minute --limit-burst 10 -j LOG #某些端口有访问没有接受的话,记到系统log中去,位置:/var/log/syslog sudo iptables -t filter -A limit-reject -p tcp -j DROP #但凡是走到这一句tcp的包,都扔了吧 sudo iptables -t filter -A limit-reject -p udp -j DROP #凡是走到这里的udp包,也扔了吧
咱就是说,也不能光设置不测试吧,这边还有对发的测试代码,
tcp的服务端:
def start_tcp_server(host='58.240.185.246', port=21110): # 创建socket对象 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: # 设置选项,允许重新使用地址,这在重启服务时避免等待 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 绑定到地址和端口 s.bind((host, port)) # 开始监听 s.listen() print(f"服务器启动成功,正在监听 {host}:{port}") while 1: # 接受客户端连接 conn, addr = s.accept() clitdata = conn.recv(1024) # 发送数据给客户端 print(f"连接地址: {addr}内容{clitdata}") conn.sendall(b'1djdhdgw') # 发送数字1,以字节形式 time.sleep(0.1) # 关闭连接 conn.close() # 启动服务 start_tcp_server()
其实普通http服务也将就能用,问题不大
python -m http.server 21110
tcp的客户端
import socket import time def send_tcp_data(ip, port, message): # 创建一个socket对象 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: try: # 连接到服务器 s.connect((ip, port)) print(f"已连接到 {ip}:{port}") # 将消息转换为字节发送 s.sendall(message.encode("utf-8")) # 接收服务器响应 response = s.recv(1) print(f"收到的响应: {response.decode()}") except socket.error as e: print(f"发送数据失败: {e}") # 使用示例 server_ip = '58.240.185.246' # 服务器的IP地址 #server_ip = 'localhost' # 服务器的IP地址 server_port = 21110 # 服务器的端口号 send_message = 'SSH-2.0-OpenSSH_8.9p1 Ubuntu-3ubuntu0.7\r\n' # 要发送的消息 for i in range(50): print(i) send_tcp_data(server_ip, server_port, send_message) time.sleep(0.1)
我这边都对发验证过了。,不管限速还是drop还是写log都是管用的。
然后,就是如何持久化了,
写到这里才想起来,除了ipv4,还有ipv6呢,得,再来一次
首先把ufw中残留的设置给删了
sudo ip6tables -t filter-F #默认表中的数据清除一下 sudo up6tables -t filter -X #非默认的链都删了
然后ip6的访问都禁了:
sudo ip6tables -t filter -A INPUT -j REJECT
然后装个辅助包固定配置:
sudo apt install iptables-persistent
sudo iptables-save > /etc/iptables/rules.v4 //如果添加了ipv4 规则,执行这步 sudo ip6tables-save > /etc/iptables/rules.v6 //如果添加了ipv6规则,执行这步
遇到个问题是ip6tables提示没有权限,对,,sudo也没有权限,不过问题不大,直接cp替换掉文件就行了
sudo systemctl stop netfilter-persistent sudo ip6tables-save > temp.log sudo cp temp.log /etc/iptables sudo mv temp.log rules.v6
ok