sysctl 参数调优不是去背参数列表,而是搞清楚每个参数背后对应着什么样的攻击场景。很多人把内核参数优化当成“安全基线”去抄,结果抄完以后该被 SYN Flood 打满的还是打满,该被 ICMP 隧道偷数据的还是照偷不误。真正有效的做法是:先理解攻击原理,再决定开哪个参数、设什么值,并且确认这个值在你的业务场景下不会把正常流量干掉。
net.ipv4.tcp_syncookies这个参数默认在 Debian 上就是 1,但很多人不知道它到底防什么。TCP SYN Flood 的本质是攻击者只发 SYN,不完成三次握手,导致服务器半连接队列被撑爆。syncookies 的机制是不再把半连接信息存在内存里,而是把关键信息编码进一个加密的 cookie,通过 SYN-ACK 发回去,等收到客户端的 ACK 再还原连接状态。这样半连接队列永远不会被占满。代价是 cookie 计算和验证会消耗少量 CPU,但在万兆网络环境下这点开销几乎可以忽略。除非你的业务是极端低延迟交易场景,否则这个参数没有关闭的理由。验证是否生效可以用 "sysctl net.ipv4.tcp_syncookies" 查看,输出为 1 即开启。
net.ipv4.tcp_max_syn_backlog这个值定义的是半连接队列的最大长度。syncookies 虽然能防止队列被占满,但在 syncookies 生效之前,系统还是会先尝试用正常队列处理。默认值通常是 256 或 512,对于面向公网的服务来说太小了。建议调整到 4096 或更高,但前提是你的内存足够。调整这个参数之前,先用 "ss -s" 看一下当前系统的半连接统计,如果经常出现 SYN-RECV 状态堆积,就说明需要加大。不要无脑设成 65535,因为每个半连接条目都会占用少量内核内存,设太大反而可能在极端情况下触发 OOM。
net.ipv4.tcp_timestamps这个参数的安全争议很大。开启时间戳可以帮助 TCP 精确计算 RTT,改善拥塞控制,但它也会泄露系统运行时间,攻击者可以通过时间戳差值推断系统启动时间,进而判断内核版本是否打了某个补丁。更危险的是,某些老版本内核的时间戳实现存在信息泄露漏洞,可以被用来推断 NAT 后面的主机数量。如果你的业务不需要精确的 RTT 测量,或者你在 NAT 后面运行服务,建议关闭:"sysctl -w net.ipv4.tcp_timestamps=0"。关闭后对性能的影响在局域网内几乎感觉不到,跨地域网络可能会有轻微影响,但安全性收益远大于这点性能损失。
net.ipv4.tcp_sack 和 net.ipv4.tcp_dsack选择性确认(SACK)和重复 SACK(DSACK)能显著提升高丢包网络下的传输效率,但它们也是内核协议栈历史上漏洞频发的重灾区。CVE-2019-11477、CVE-2019-11478、CVE-2019-11479 这一串 SACK Panic 漏洞就是典型例子,攻击者可以构造特殊序列的 SACK 包导致内核崩溃或资源耗尽。如果你已经升级到 Debian 的最新稳定内核,这些已知漏洞都已被修复,SACK 可以保持开启。但如果你运行的是无法频繁升级的老系统,关闭 SACK 是降低攻击面的有效手段。关闭方法:"sysctl -w net.ipv4.tcp_sack=0" 和 "sysctl -w net.ipv4.tcp_dsack=0"。注意,关闭后在大带宽长距离传输场景下吞吐量会明显下降,所以这是安全与性能的取舍,不是一刀切。
net.ipv4.conf.all.rp_filter反向路径过滤是防 IP 欺骗的基础机制。设为 1 时,内核会检查入站数据包的源地址是否可以通过接收该包的接口路由回去,如果路由表显示这个源地址应该从另一个接口进来,就丢弃该包。这在多宿主主机上尤其重要,可以防止攻击者伪造内网 IP 从公网接口发起攻击。Debian 默认值是 0,也就是不检查。建议设为 1:"sysctl -w net.ipv4.conf.all.rp_filter=1"。如果你的主机做路由器用了非对称路由,需要设为 2,也就是松散模式,只检查源地址是否可达,不强制要求接口一致。注意这个参数有 all 和 default 以及 per-interface 三个层级,all 的修改会影响所有接口,但已有接口需要单独设置或重启网络服务才能生效。
net.ipv4.icmp_echo_ignore_all这个参数直接决定主机是否响应 ping。很多安全指南建议关闭,理由是减少信息暴露和防止 ICMP Flood。但实际上完全禁止 ICMP Echo Reply 会破坏 PMTUD(路径 MTU 发现),导致某些网络环境下 TCP 连接建立后传输数据时卡死。更合理的做法是保留 ICMP 响应,但做速率限制。所以这个参数建议保持默认的 0,不忽略 ping。真正防 ICMP Flood 应该用 iptables 的 limit 模块做速率限制,而不是在内核层面一刀切。
net.ipv4.icmp_echo_ignore_broadcasts 和 net.ipv4.icmp_ignore_bogus_error_responses这两个参数分别用于忽略发往广播地址的 ICMP 请求和忽略伪造的 ICMP 错误响应。前者可以防止主机被用作 Smurf 攻击的放大器,后者可以防御某些畸形 ICMP 包导致的内核异常。Debian 默认都已经是 1,也就是开启状态。检查确认一下即可,不需要修改。如果发现是 0,立即改为 1。
net.ipv4.conf.all.accept_source_route 和 net.ipv4.conf.all.accept_redirects源路由选项允许发送方指定数据包的转发路径,这在现代网络中几乎没有任何合法用途,反而是攻击者用来绕过防火墙策略、探测内网拓扑的利器。ICMP 重定向同样如此,攻击者可以伪造 ICMP 重定向消息篡改主机的路由表。这两个参数必须设为 0:"sysctl -w net.ipv4.conf.all.accept_source_route=0" 和 "sysctl -w net.ipv4.conf.all.accept_redirects=0"。同时也要把 default 和各个接口的对应参数都设为 0,确保万无一失。
net.ipv4.conf.all.secure_redirects 和 net.ipv4.conf.all.shared_mediasecure_redirects 控制是否只接受来自默认网关的 ICMP 重定向,比完全接受好一点,但仍然是风险,直接设为 0。shared_media 这个参数很多人没注意过,它决定内核是否假设网络是共享介质的,如果设为 1,内核在发送 ICMP 重定向之前不做额外的源地址检查。现代网络几乎都是交换式以太网,不存在共享介质,这个参数应该设为 0,减少不必要的 ICMP 行为暴露。
net.ipv4.conf.all.log_martians火星包是指源地址或目的地址在路由表中不可达、或者源地址明显是保留地址却出现在公网接口上的数据包。开启火星包日志可以帮助你发现网络中的配置错误或正在进行的欺骗攻击。建议设为 1:"sysctl -w net.ipv4.conf.all.log_martians=1"。日志会输出到内核日志,可以用 "dmesg" 或 journalctl 查看。如果日志量太大,说明你的网络确实有问题,需要排查而不是关掉日志。
net.ipv4.ip_forward除非你的 Debian 系统确实在做路由器或 NAT 网关,否则这个参数必须为 0。开启 IP 转发会让主机变成路由器,攻击者可以利用它穿透网络隔离。很多容器和虚拟化环境会自动开启这个参数,部署完成后一定要检查:"sysctl net.ipv4.ip_forward",如果输出是 1 且你不需要转发功能,立即关闭。
net.ipv6.conf.all.disable_ipv6如果你的业务完全不需要 IPv6,最安全的做法是在内核层面禁用它。不要以为没有配置 IPv6 地址就是安全的,链路本地地址自动配置、ICMPv6 邻居发现等机制仍然会运行,攻击者在同一二层网络内可以通过 IPv6 相关协议发起攻击。Debian 上彻底禁用 IPv6 的方法是在 "/etc/default/grub" 的内核启动参数中加入 "ipv6.disable=1",然后 "update-grub" 重启。如果不想重启,可以通过 sysctl 逐个接口禁用:"sysctl -w net.ipv6.conf.all.disable_ipv6=1"。
net.core.rmem_default, net.core.wmem_default, net.core.rmem_max, net.core.wmem_max这四个参数控制 socket 缓冲区的默认值和最大值。从安全角度看,缓冲区太小容易被放大攻击打满导致丢包,缓冲区太大则可能被慢速攻击消耗内存。对于面向公网的服务,建议将最大值调到 16MB 或更高:
sysctl -w net.core.rmem_max=16777216 sysctl -w net.core.wmem_max=16777216
默认值保持系统默认即可,让应用程序根据需要在代码中通过 setsockopt 动态调整。这样既能保证高吞吐场景下的性能,又不会让每个 socket 都占用大量内存。
net.core.netdev_max_backlog这个参数定义的是网络接口接收队列满时,内核在软中断处理中可以排队的数据包最大数量。如果网卡收包速度超过内核处理速度,超出部分会被丢弃。在遭受 DDoS 攻击时,适当增大这个值可以缓冲突发流量,给上层防护机制争取时间。建议设为 5000 或更高:"sysctl -w net.core.netdev_max_backlog=5000"。但不要超过 65535,过高的值会导致软中断处理延迟过大,反而拖垮系统。
net.ipv4.tcp_orphan_retries 和 net.ipv4.tcp_fin_timeout这两个参数用于控制 TCP 连接关闭阶段的行为。tcp_fin_timeout 默认是 60 秒,tcp_orphan_retries 默认是 0(表示使用内核计算值,通常为 8 次重试)。攻击者可以发起大量 FIN-WAIT-2 状态的连接来消耗内存。将 tcp_fin_timeout 降到 30 秒或更低可以加速回收孤儿连接:"sysctl -w net.ipv4.tcp_fin_timeout=30"。tcp_orphan_retries 设为 2 或 3 可以限制重试次数,避免长时间占用资源。注意调低这些值可能导致在极端网络环境下正常连接被提前断开,但公网服务通常可以接受这种权衡。
net.ipv4.tcp_max_orphans这个参数限制系统级别的孤儿 socket 总数。所谓孤儿 socket 是指已经与进程脱离关联、但还在内核中等待清理的 TCP 连接。如果数量超过这个阈值,新产生的孤儿连接会被直接 Reset。默认值通常根据内存自动计算,但在遭受特定攻击时可能不够。手动设为 65536 或更高可以提供更大的缓冲空间,同时配合 tcp_fin_timeout 的调低,确保孤儿连接能被及时回收而不是堆积。
net.ipv4.tcp_keepalive_time, net.ipv4.tcp_keepalive_intvl, net.ipv4.tcp_keepalive_probesTCP Keepalive 机制可以帮助清理死连接,防止资源被长时间占用。默认的 keepalive_time 是 7200 秒,也就是两个小时,对于公网服务来说太长了。建议调整为 600 秒:"sysctl -w net.ipv4.tcp_keepalive_time=600"。探测间隔 intvl 设为 60 秒,探测次数 probes 设为 3 次。这样一条死连接最多在 600+60×3=780 秒后就会被清理。注意这些参数是系统级别的默认值,应用程序可以通过 setsockopt 覆盖,所以还需要确认你的服务程序是否正确使用了 SO_KEEPALIVE 选项。
kernel.kptr_restrict 和 kernel.dmesg_restrict这两个参数直接影响信息泄露的难易程度。kptr_restrict 设为 1 时,普通用户通过 /proc/kallsyms 等接口看到的内核指针会被替换为 0,防止攻击者利用内核地址布局绕过 KASLR。设为 2 则完全隐藏。建议设为 2:"sysctl -w kernel.kptr_restrict=2"。dmesg_restrict 设为 1 可以禁止普通用户读取内核日志,防止通过 dmesg 泄露内核地址或其他敏感信息:"sysctl -w kernel.dmesg_restrict=1"。这两个参数对日常运维影响很小,root 用户不受限制,但能有效提高本地提权攻击的难度。
kernel.yama.ptrace_scopeptrace 系统调用允许一个进程检查和修改另一个进程的内存和寄存器,这是调试器的核心机制,但也是进程注入和数据窃取的常用手段。yama.ptrace_scope 设为 1 时,只有父进程可以 ptrace 子进程,或者子进程显式授权。设为 2 则只允许 root 使用 ptrace。对于生产服务器,建议设为 2:"sysctl -w kernel.yama.ptrace_scope=2"。如果你的服务依赖 gdb 调试或 perf 性能分析,需要评估影响,但安全敏感环境应该尽可能限制 ptrace。
kernel.randomize_va_space地址空间布局随机化(ASLR)是现代操作系统的基础安全机制。Debian 默认值是 2,表示对栈、堆、共享库、mmap 区域都启用随机化。检查确认即可:"sysctl kernel.randomize_va_space",输出应为 2。如果发现是 0 或 1,立即修改为 2。这是防御缓冲区溢出攻击的关键防线,没有理由关闭。
fs.suid_dumpable这个参数控制 setuid 程序崩溃时是否生成 core dump。设为 0 时禁止生成,设为 1 时允许生成但只有 root 可读,设为 2 时完全允许。core dump 中可能包含内存中的敏感数据,如密码、密钥、数据库连接串等。生产环境建议设为 0:"sysctl -w fs.suid_dumpable=0"。如果你的应用需要 core dump 来做事后分析,可以用 "ulimit -c" 在进程级别控制,而不是全局放开。
kernel.sysrqSysRq 键组合允许在系统挂死时执行底层操作,包括强制重启、同步文件系统、杀掉所有进程等。对于物理服务器,保留 SysRq 是最后一道救援手段。但对于云服务器或远程管理的 VPS,攻击者如果能接触到控制台,SysRq 就是一个巨大的安全隐患。建议设为 0 完全禁用,或者设为 1 只允许安全的操作(如同步、卸载文件系统),禁止重启和关机。具体值取决于你的运维需求和物理访问控制情况。
将参数持久化所有通过 "sysctl -w" 设置的参数在重启后都会丢失。持久化配置需要写入 "/etc/sysctl.conf" 或 "/etc/sysctl.d/" 目录下的配置文件。Debian 默认读取 "/etc/sysctl.conf" 和 "/etc/sysctl.d/*.conf"。建议创建一个专门的安全配置文件,比如 "/etc/sysctl.d/99-security.conf",把上述所有参数写入,然后执行 "sysctl -p /etc/sysctl.d/99-security.conf" 立即生效。格式就是每行一个 "参数=值",井号开头的行为注释。修改完成后用 "sysctl -a" 逐个检查确认实际生效值,不要相信配置文件写对了就一定生效,有些参数可能被其他配置文件覆盖,或者受限于内核版本不支持。
最后强调一点:sysctl 调优不是一次性工作。内核版本升级、业务模型变化、攻击手法演进,都会影响参数的有效性和适用性。把这些参数纳入配置管理和监控体系,定期审计实际值是否与预期一致,才是真正落地的安全实践。
