在Ubuntu服务器安全加固中,rp_filter(反向路径过滤)严格模式是防止IP欺骗攻击的核心手段,而路由验证则确保数据包的来源路径合法。具体做法是将内核参数net.ipv4.conf.all.rp_filter和net.ipv4.conf.default.rp_filter都设置为2(严格模式),同时配合net.ipv4.conf.all.log_martians=1开启异常包日志记录。这套配置能有效阻断伪造源IP的DDoS攻击和中间人劫持尝试,是生产环境中不可跳过的基础安全项。

很多运维人员只知道开启rp_filter,却不清楚为什么要设成"2"而不是"1",也不了解路由验证的具体机制。下面从原理到实操,把这套安全配置讲透。

什么是rp_filter以及为什么要开严格模式

rp_filter的全称是Reverse Path Filter,中文叫反向路径过滤。它的工作原理很简单:当一个数据包到达网卡时,内核会检查这个包的源IP地址,然后去查路由表,看从这个源IP过来的数据包是否应该从当前这个接口进入。如果路由表显示源IP应该从别的接口进来,那这个包就是可疑的,直接丢弃。

rp_filter有三个值:0表示关闭过滤,1表示松散模式,2表示严格模式。松散模式只要源IP能从任意接口路由到本机就放行,而严格模式要求源IP必须从接收该包的接口本身路由回来才放行。对于多网卡服务器、做NAT转发的机器、或者有非对称路由的环境,严格模式是最安全的选择,因为它杜绝了IP欺骗的可能性。

举个实际场景:攻击者伪造源IP为你内网机器的地址发送数据包,如果rp_filter是0或者1,这些伪造包可能被接受。设成2之后,内核发现这个源IP按路由表不应该从当前接口进来,直接丢掉,攻击链就断了。

Ubuntu中查看和修改rp_filter的具体步骤

先查看当前系统的rp_filter设置值,执行以下命令:

sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.default.rp_filter
sysctl net.ipv4.conf.eth0.rp_filter

注意,all是全局设置,default是默认值,而eth0这种是针对具体网卡的设置。具体网卡名称用ip a命令查看。在Ubuntu中,网卡名称通常是ens33、ens160、eth0这类格式。

临时修改(重启后失效)的命令:

sudo sysctl -w net.ipv4.conf.all.rp_filter=2
sudo sysctl -w net.ipv4.conf.default.rp_filter=2
sudo sysctl -w net.ipv4.conf.all.log_martians=1

永久生效需要编辑sysctl配置文件:

sudo nano /etc/sysctl.conf

在文件末尾添加以下内容:

# 反向路径过滤 - 严格模式
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2

# 记录异常数据包(火星包)
net.ipv4.conf.all.log_martians = 1

# 禁止ICMP重定向(防止路由欺骗)
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0

# 启用源地址验证
net.ipv4.conf.all.src_valid_mark = 1

保存后执行sudo sysctl -p使配置立即生效。如果你有多个网卡,建议对每个网卡单独设置rp_filter=2,避免all覆盖不全的情况。

路由验证的深层机制与注意事项

路由验证不仅仅是rp_filter一个参数,它是一套组合策略。核心逻辑是:内核在收到每个入站数据包时,都要做一次"源IP是否合法"的判断。这个判断依赖于内核的FIB(Forwarding Information Base,转发信息库),也就是路由表。

严格模式下,内核会执行最精确的检查——它不仅看源IP是否可达,还要看是否从接收接口可达。这意味着如果你的服务器有两块网卡,一块连外网,一块连内网,从外网进来的包如果源IP是内网段的地址,严格模式会直接丢弃。这正是我们想要的效果。

但这里有一个常见坑:如果你的服务器做了策略路由(policy routing),或者有多个默认网关,严格模式可能会误杀正常流量。解决办法是对不需要严格过滤的接口单独设为0或者1,或者调整路由策略让每个接口的路由表都能正确回指。

另外,net.ipv4.conf.all.accept_redirects和send_redirects这两个参数也和路由验证密切相关。ICMP重定向消息可以被攻击者利用来篡改路由表,所以生产环境必须关掉。log_martians=1则让内核把被丢弃的异常包记录到系统日志中,方便你用dmesg或者journalctl排查问题。

多网卡环境下的精细化配置方案

生产服务器通常不止一块网卡。假设你的Ubuntu机器有ens33(外网)和ens34(内网)两块网卡,推荐这样配置:

# 全局默认
net.ipv4.conf.default.rp_filter = 2

# 外网接口 - 严格过滤
net.ipv4.conf.ens33.rp_filter = 2

# 内网接口 - 如果内网有复杂路由,可以设为1
net.ipv4.conf.ens34.rp_filter = 1

# 或者全部严格
net.ipv4.conf.ens34.rp_filter = 2

判断标准是:如果内网接口的路由是对称的(去和回走同一条路),就设2;如果内网有非对称路由或者做了负载均衡,设1更稳妥。设错了不会导致系统崩溃,只会让部分正常包被丢弃,通过日志可以快速定位。

查看被丢弃的包数量:

dmesg | grep -i "martian"
journalctl -k | grep -i "martian"

如果看到大量martian包,说明要么有攻击,要么配置有误需要调整。

配合iptables和防火墙的协同防护

rp_filter是内核层面的防护,属于第一道防线。在此基础上,还应该用iptables或nftables做更细粒度的控制。比如明确允许哪些源IP段访问哪些端口:

# 只允许特定IP访问SSH
sudo iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j DROP

# 允许已建立连接的回包
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 记录并丢弃其他入站包
sudo iptables -A INPUT -j LOG --log-prefix "IPTABLES-DROP: "
sudo iptables -A INPUT -j DROP

Ubuntu 22.04以后默认用nftables替代iptables,语法有所不同但逻辑一致。内核层的rp_filter加上防火墙层的规则,形成纵深防御,安全性会大幅提升。

验证配置是否生效以及持续监控

配置完成后,用以下命令验证所有参数是否正确加载:

sysctl -a | grep rp_filter
sysctl -a | grep log_martians
sysctl -a | grep accept_redirects

建议写一个简单的监控脚本定期检查关键参数有没有被意外修改:

#!/bin/bash
EXPECTED_RP=2
ACTUAL_RP=$(sysctl -n net.ipv4.conf.all.rp_filter)
if [ "$ACTUAL_RP" != "$EXPECTED_RP" ]; then
    echo "WARNING: rp_filter changed to $ACTUAL_RP" | logger -t security-check
fi

把这个脚本放到cron里每小时跑一次,确保配置不被其他程序或管理员误改。

常见问题排查与最佳实践总结

实际部署中最常遇到的问题有三个:一是多网卡非对称路由导致正常包被丢,解决方法是对特定接口降级为rp_filter=1;二是容器或虚拟化环境中宿主机和容器共享网卡,需要在容器内单独配置;三是某些老旧应用依赖松散路由,需要在防火墙层面做白名单而不是全局严格过滤。

最佳实践总结:生产环境默认全部设2,内网复杂环境按需降级;一定要开log_martians便于排查;配合accept_redirects=0防止路由欺骗;用防火墙做第二层防护;定期审计参数状态。这套组合拳下来,IP欺骗类攻击基本可以被挡在门外。

安全加固从来不是一次性的工作,而是持续的过程。rp_filter严格模式只是其中一个环节,但它是成本最低、效果最直接的手段之一。在Ubuntu服务器上花五分钟改几行配置,就能堵住一个常见的攻击面,这笔账怎么算都划算。