首页 / 资讯中心 / 文章详情

Linux NTP服务加固:防范DDoS放大攻击实战指南

Linux NTP服务加固:防范DDoS放大攻击实战指南 ★ FEATURED ARTICLE
NTP服务可能是Linux服务器上最不起眼却又最容易变成DDoS放大器的基础设施。默认配置一旦暴露到公网攻击者只要构造一条几十字节的查询报文就能让服务器向伪造的源IP地址吐出几百倍体积的响应流量——这就是NTP放大攻击。我见过不少团队在防DDoS时只盯着HTTP和SYN洪泛结果忽略了一台开着monlist功能的老旧ntpd最后整个机房的入口带宽被打满业务全部瘫痪。这个场景适合所有Linux运维、SRE和安全工程师服务器对外开放时间同步功能没问题但被互联网上的陌生人拿去当攻击武器就不能不管了。下面我从NTP服务配置、服务端加固到防火墙限速把每一步讲清楚顺便把踩过的坑也一并列出来。1. 为什么NTP会变成攻击跳板1.1 放大攻击的原理小请求大流量NTP服务基于UDP协议默认端口是123。UDP和TCP最大的区别在于它没有握手过程应用层收到数据包后会直接处理而且源IP地址可以伪造。攻击者不需要完成三次握手只需要把源IP写成受害者的IP把一条构造好的NTP查询命令发给一台互联网上开放的NTP服务器NTP服务器就会把响应数据包原路返回给“源IP”——也就是受害者。这种反射本身不会造成什么威胁关键在于放大倍数。NTP协议里面有一个历史悠久的控制查询功能叫monlist旧版ntpd允许客户端查询这台服务器的内存监控列表也就是最近一段时间内和它通信过的客户端记录。查询请求很小可能只有几十字节但响应报文会把整个列表打包送出去几百个客户端记录塞在一个响应包里放大倍数可以达到几十倍甚至几百倍。攻击者只要拿到一批开放的NTP服务器同时向不同的服务器发送伪造源IP的monlist请求在受害者那边就会叠加成数Gbps的UDP流量风暴。我举个更直观的例子一台普通服务器上行带宽假设是1Gbps攻击者用200台放大倍数100倍的NTP服务器做辅助不用自己出多少带宽就能把受害者的入口带宽打满。这就是NTP放大攻击比SYN洪泛更难缠的地方——攻击流量不是来自攻击者自己的IP而是来自遍布各地的NTP服务器追踪和封禁起来非常麻烦。1.2 问题根源在配置放开不等于安全很多人会问NTP服务不是用来同步时间的吗为什么会有这么大的杀伤力这里要说清楚NTP协议本身没问题问题出在“配置过于开放”。很多发行版默认的ntpd配置文件里restrict部分写得比较宽松或者干脆没有明确限制。结果就是任何互联网上的陌生客户端都能向这台服务器发送查询命令比如monlist、peers查询、版本查询等等。这些查询命令用不上多少带宽但服务器返回的响应数据量远大于请求数据量等于把一个普通的时钟服务器变成了免费的流量放大器。更麻烦的是有些人为了图省事直接在云主机安全组里放行UDP 123端口但没有在服务端限制谁能访问。时间同步确实通了攻击者也跟着通了。你原本只是想让自己公司的办公网能同步时间结果整个公网的人都能用这台服务器发动反射攻击。所以NTP安全的第一原则不是“要不要开UDP 123”而是“服务端允许谁查询、允许查什么”。控制好这两点放大攻击也就失去了立足点。1.3 影响范围不止是被打的受害者一次NTP放大攻击受害者肯定首当其冲入口带宽被打满业务中断。但受影响的不只是受害者NTP服务器本身会被拖入攻击链条。它的大流量响应会让自己的出口带宽飙升服务器负载升高正常的时间同步请求也会被挤掉。开放的NTP服务器会被安全社区拉黑甚至被上游机房投诉影响服务器口碑和被Future用。中间链路也会被波及。大量UDP流量在网络中穿越路由器、交换机、防火墙都要消耗处理能力和带宽还可能影响同机房其他用户。换句话说只要你有一台未加固的NTP服务暴露在公网哪怕自己没被打也可能在不知情的时候成为攻击别人的“帮凶”。这个影响范围比很多人想象的要大得多。2. 动手前先摸清家底基线检查与服务选型2.1 先搞清楚你正在跑的版本和现状开始配置之前得先确认自己服务器上到底跑的是什么NTP实现、什么版本、监听在哪个地址。很多线上事故其实就坏在“我记得配过”实际上服务从安装到现在都没重启过配置。打开终端先跑这几条命令ntpd --version chronyd --version ss -ulnp | grep :123 systemctl list-units | grep -E ntp|chrony如果返回里能看到ntpd执行ntpd --version看看版本号。如果版本低于4.2.8p16就得尽快升级因为旧版本在monlist处理上有明显漏洞哪怕加了disable monitor处理某些畸形控制报文时也会产生异常响应。如果看到的是chronyd说明系统用的是chrony这个实现从设计上就更安全一些继续往下看配置就好。再看ss -ulnp的输出重点看UDP 123监听地址是0.0.0.0还是内网IP。如果是0.0.0.0说明服务对所有的网卡接口都提供服务紧接着检查防火墙和安全组对UDP 123的来源控制。我见过有人的NTP服务监听在公网IP上但安全组只允许内网来源这也行但依赖安全组不是长久之计还是要在服务端配置访问控制。最后确认一下自己是不是真的需要向外提供服务。很多服务器只是作为NTP客户端去同步时间根本不需要对外开放UDP 123端口这种情况下直接把入方向的UDP 123在防火墙里拦掉就行服务端配置都省了。2.2 chrony还是ntpd我的选型理由现在的Linux发行版上常见的两个NTP实现就是chrony和openntpd/ntpd。我的建议是新部署或者能切换的环境优先用chrony理由很实际chrony默认不提供monlist这类控制查询响应配置里没有servers这种容易出问题的模式。chrony支持网络时间安全协议NTS虽然目前公网NTS服务器还不多但对你以后的需求扩展有帮助。chrony的同步算法在虚拟机、云主机这种网络抖动比较大的环境里表现更好收敛速度比老ntpd快。chrony的配置语法更清晰访问控制用allow/deny两条指令就能说清楚不像ntpd的restrict有大串参数需要记。如果环境里必须用ntpd也不是不行只是要更仔细地检查配置文件把所有可能暴露的控制查询关掉。我给两个方案都写了配置下面分别说明。3. 服务端安全配置让NTP既可用又不可滥用3.1 chrony配置权限、访问控制与响应限制如果你用的是chrony配置文件一般在/etc/chrony/chrony.conf。我拿来生产环境用的配置大概是这样的# /etc/chrony/chrony.conf pool 0.pool.ntp.org iburst bindaddress 127.0.0.1 bindaddress 192.168.20.10 allow 192.168.20.0/24 allow 10.0.0.0/8 local stratum 10 ratelimit interval 4 burst 8 cmdport 0逐条说下我为什么这么写pool 0.pool.ntp.org iburst是让服务器从公共NTP池同步时间iburst的作用是刚启动时加快首次同步速度。如果服务器处于内网隔离环境可以把这一行删掉用local stratum 10让它在本地作为时间源但这种情况要特别确认没有公网客户端能访问。bindaddress指定chrony监听在哪些地址上。这里写上了回环地址和内网IP公网IP如果不需要对外服务就不写在里面。注意bindaddress在chrony里可以写多行确保每张需要的网卡都有对应地址。如果业务上确实需要让公网用户使用这台NTP服务器那你得评估清楚后果并在外层防火墙做严格的ACL而不是让所有人都能访问。allow是本配置最关键的两行它决定了哪些来源的客户端可以和这台服务器同步时间。我只允许内网的两个网段访问公网来源直接进不了服务层。deny指令的优先级比allow高如果你发现某个来源在allow列表里但需要单独拒绝可以再加一行deny 192.168.20.3。ratelimit interval 4 burst 8是chrony提供的响应限速能力。interval 4表示以2的4次方秒也就是16秒为一个基础窗口burst 8表示允许短时间内的突发包最多8个。这个参数的意思是每个客户端IP在单位时间内能收到的响应包数量是受限的。这样即使有人伪造源IP来查询服务器给每个“源IP”的响应也不会无限放大反射放大倍数被压下来。cmdport 0把chrony的管理命令端口关掉了外部通过chronyc命令连接会被拒绝。有些环境还需要运维人员用chronyc查看同步状态那就别设成0改成cmdallow 127.0.0.1只放本机回环来源其他来源一律不让。改完配置后执行systemctl restart chronyd chronyc sources -vsources -v能看到当前时间源的连接状态如果系统时间和实际时间误差比较大可能需要等几分钟让chrony完成step/slew调整。3.2 ntpd配置与restrict详解如果因为各种原因必须用ntpd配置文件一般在/etc/ntp.conf。下面是一个经过压测验证的安全配置模板# /etc/ntp.conf restrict -4 default kod notrap nomodify nopeer noquery restrict -6 default kod notrap nomodify nopeer noquery restrict 127.0.0.1 restrict 192.168.0.0 mask 255.255.0.0 nomodify notrap nopeer server 0.pool.ntp.org iburst server 1.pool.ntp.org iburst disable monitor driftfile /var/lib/ntp/drift这里最关键的是第一行和第二行的restrict -4 default和restrict -6 default。它给所有默认客户端套上了限制nomodify不允许客户端修改服务器的时间或配置。nopeer不允许客户端和服务器建立对等关系防止被用来探测或建立非对称主动模式。noquery不允许客户端查询服务器状态信息这是关闭monlist等控制查询的关键。notrap不允许客户端发送控制消息来设置陷阱。kod对可疑的客户端响应Keep Out of Date包起到一种“请离开”的提醒作用。注意restrict default后面必须同时带上noquery和nomodify缺一个都不行。我之前见过有人只写了nomodify notrap漏掉了noquery结果monlist查询还是能正常返回攻击面依然存在。restrict 127.0.0.1这一行保持默认意思是本机不受上面那些限制的约束这样本地的ntpq命令还能正常查看状态。内网网段那行restrict 192.168.0.0 mask 255.255.0.0 nomodify notrap nopeer允许这个网段的机器同步时间但同样不能修改参数、不能建peering等。disable monitor是这段配置的第二个命门。它会禁用内建到ntpd的monist监控列表功能即使有人发送monlist查询服务器也不会返回历史客户端记录。从4.2.8p16开始社区已经缩紧了monlist的行为但显式写上disable monitor能让很多审计工具直接看到你的防护姿态建议保留。改完后执行ntpd -gq systemctl restart ntp ntpq -pn用ntpq -pn查看同步结果如果输出里能看到带*或前缀的时间源说明同步链路正常。3.3 更进一步的加固关闭远程管理接口与启用NTS无论你用的是chrony还是ntpd有几个额外动作值得做。第一确认管理端口不向外服务。ntpd的ntpdc和ntpq走的是不同控制通道默认情况下会监听在123端口上。通过restrict ... noquery能挡住大部分查询但为了保险建议在防火墙层直接限制来源地址访问UDP 123。如果只是内网使用就只放行内网网段来源。第二如果你有内部认证需求可以为NTP启用对称密钥验证。ntpd和chrony都支持在配置里指定key和keyfile比如key 1 0x0123456789abcdef restrict 192.168.0.0 mask 255.255.255.0 nomodify notrap nopeq noquery客户端同步时携带正确的密钥信息服务器才接受请求。这个方案能防止伪造源IP的请求被处理因为服务器要先验证请求里的MAC字段而攻击者拿不到密钥。缺点是密钥分发和管理有一定成本适合对时间敏感的内网环境。第三如果条件允许考虑启用NTS。chrony从4.2版本开始支持NTS配置起来也简单pool time.example.com iburst ntsNTS通过TLS协议先做密钥协商再对NTP报文做加密认证天然抵御伪造和放大。目前公共NTS服务器还比较少但如果你自己管理多台服务器完全可以在内网搭一个NTS时间源让其他节点都用NTS同步。这样即使某个节点的公网暴露攻击者也很难利用它做源地址伪造的放大攻击。4. 网络层联动防火墙限速与上游清洗4.1 用iptables按源IP限制UDP 123请求服务端配置完成后网络层还要铺一层防护。最常用的手段是限制单位时间内来自同一个源IP的UDP 123包数量。iptables里有一个recent模块可以按IP记录最近出现的数据包时间非常适合作UDP小包限速。我常用的规则组合是这样iptables -A INPUT -p udp --dport 123 -m recent --name NTP --rcheck --seconds 60 --hitcount 6 -j DROP iptables -A INPUT -p udp --dport 123 -m recent --name NTP --set -j ACCEPT规则顺序不能反。第一条判断如果这个源IP在最近60秒内已经出现过6次就DROP掉之后的包。第二条负责把这个源IP记到recent记录里同时允许它访问NTP服务。第一个包进来时第一条的rcheck判断命中数为0跳到第二条记录并接受当同一个IP在短时间内发到第6个包时第一条命中后面的包被丢弃。为什么这样能防NTP放大攻击者利用服务器做反射时发送给NTP服务器的查询包源IP是受害者的IP。受害者的IP会迅速触发recent的丢弃规则服务器给受害者回应的包数量被限制在“每分钟最多5个”左右放大效果大打折扣。合法NTP客户端的同步频率通常是一分钟一次甚至几分钟一次所以这个限制基本不影响正常使用。要注意如果NTP服务器本身面向大量公网客户端提供服务每分钟6次的上限可能太苛刻。可以把hitcount调到10或者20或在--rcheck前增加--seconds 120棉延长统计窗口。但一定不要改成完全不限。规则设置完成后执行iptables-save /etc/iptables/rules.v4否则重启后规则就没了。用systemd管理iptables的环境一般会自动加载/etc/iptables/rules.v4如果你的发行版不是这样记得写一个systemd unit或者启动脚本确保规则持久化。4.2 用nftables写更清晰的网络层规则新发型版本很多已经默认使用nftables了。如果你熟悉iptables其实不需要强转但nftables写起来更直观。一个最小化安全的NTP网络层配置可以这样写nft add table inet ntp_guard nft add chain inet ntp_guard input { type filter hook input priority 0; policy accept; } nft add rule inet ntp_guard input udp dport 123 ct state new limit rate over 10/minute burst 20 packets drop nft add rule inet ntp_guard input udp dport 123 accept这段规则的意思是对新建的UDP 123连接做总体限速超过每分钟10个包并且突发超过20个就直接丢。适合保护那些主要面向内网、只给少数客户端使用的NTP服务。如果要把限速精确到每个源IPnftables没有现成字段可以直接匹配我会选择用set来做。以下是一个“只允许指定网段访问NTP”的白名单配置nft add table inet ntp_guard nft add chain inet ntp_guard input { type filter hook input priority 0; policy drop; } nft add set inet ntp_guard allowed_clients { type ipv4_addr; flags interval; elements { 192.168.0.0/16, 10.0.0.0/8 } } nft add rule inet ntp_guard input ip saddr allowed_clients udp dport 123 accept nft add rule inet ntp_guard input udp dport 123 drop这样只有内网网段能访问NTP服务其他来源连到UDP 123的包直接被丢。相比刚才的iptables近期模块方案这种白名单更干脆从根源上封死了陌生来源利用放大攻击的可能。4.3 流量已经变大时往上联合和降损如果NTP放大流量已经到了Gbps级别单台服务器上的防火墙规则已经扛不住因为流量是在你服务器入口之前就把带宽打满的。这时候要做的不只是优化服务端还要往上联动尽快联系上游或云厂商开启流量清洗。清洗中心会把目标端口的UDP flood流量吸走再把干净流量回注。攻击特征是四层UDP流量清洗规则只需要识别源端口123或目的端口123的NTP报文就能做粗粒度过滤。在骨干出口布置黑洞路由。如果单个IP被打到无法承受可以直接把该IP的流量全部黑洞掉先保其他业务。这会牺牲这台NTP服务器的可用性但总比整个网段都瘫痪要好。如果NTP服务器本身不需要面向公网立刻把边界防火墙上的UDP 123改为只允许指定来源。宁可临时牺牲外部同步也不要继续裸奔。坦白说流量清洗和黑洞路由不是每个团队都有条件做。对一个中小型业务来说把NTP服务关掉或者只内网开放远远比“开放出去然后被打”要划算。公共NTP的运维责任很重没有足够的抗D能力之前不要轻易把自己的服务器做成公网NTP节点。5. 上线验证与日常巡检5.1 先自测再放流量配置改完不能看一眼配置就算完事。我会按照下面这套流程做上线验证先从服务器本机发起查询确认同步状态正常chronyc sources -v chronyc tracking对于ntpd环境ntpq -pn ntpdc -c sysinfochronyc sources -v能看到每个时间源是否处于可接受状态。如果显示^*表示已同步^-表示不可用需要检查上游网络。然后验证服务端的访问控制是否生效。找一个不受信任的IP来源或者直接用外部机器执行ntpdc -c monlist 服务器IP正常加固后的服务器这个请求应该超时或者被拒绝。如果你用nmap做端口扫描可以选udp/123的ntp相关脚本nmap -Pn -sU -p 123 --script ntp-monlist 服务器IP结果里如果出现ERROR: No response或者filtered说明服务端已经屏蔽了这些查询。如果返回了很长的列表说明配置还有漏洞立刻回去检查disable monitor和restrict noquery。再用UDP包捕获看一眼实际流量。可以这样抓取端口123观察是否有异常来源tcpdump -i eth0 -n udp and port 123 -c 50正常内网环境下应该只看到自己网段客户端的同步请求如果出现大量不同源的UDP 123包就要警觉了。5.2 日志、监控和告警别留空白NTP流量平时很低调但这不代表它不需要监控。很多攻击发生前会有一段“探测期”攻击者先扫描一大批开放服务器记录端口和版本然后再组织流量。如果服务器上有访问日志你完全能提前发现异常。chrony的日志配置在/etc/chrony/chrony.conf里可以用log指令开启log tracking measurements statistics logdir /var/log/chronyntpd的统计日志默认写在/var/log/ntpstats通过statsdir配置目录。日志里能看到每一次客户端请求的大致情况不过ntpd默认不会记录每个查询来源想要更细的来源记录还是得靠防火墙日志或者抓包。我在防火墙日志里加过一条规则给被丢弃的NTP包做前缀标记iptables -A INPUT -p udp --dport 123 -m recent --name NTP --rcheck --seconds 60 --hitcount 6 -j LOG --log-prefix NTP-FLOOD 打日志会消耗一点CPU但能在攻击发生时立刻找到阻塞来源。配合告警系统一旦一分钟内被丢弃的UDP 123包数量超过阈值就通知这个阈值通常建议设成平时正常请求的3倍左右。内网部署的话每秒超过10个包基本就有问题。5.3 定期升级和配置审查NTP的加固不是一次性的事。老版本会在后续CVE里被挖出更多问题操作系统安全补丁必须跟上。我建议每月或者每个发布周期做一次例行检查chronyd --version ntpd --version版本号明显偏老的时候直接通过系统的包管理器升级。升级后重新检查配置因为有些包升级后可能会改写配置文件或者改变默认行为。配置审查更重要。每一次变更都保留备份变更后要复核以下四个点UDP 123端口是不是只暴露给指定的网段。restrict default里有没有带noquery和nomodify。disable monitor是否存在。chrony的cmdport 0或cmdallow 127.0.0.1是否正确配置。这四个点只要有一个漏掉服务器就可能再次成为NTP放大攻击的跳板。我见过不止一次“上次升级配置文件被默认覆盖了restrict全没了”的情况所以审查配置时不要想当然直接打开文件用关键字grep一遍更靠谱grep -E ^(restrict|disable monitor|cmdport|allow|deny) /etc/chrony/chrony.conf /etc/ntp.conf6. 常见问题速查与踩坑记录6.1 高频问题速查表现象可能原因解决办法局域网客户端同步时间失败防火墙没放行UDP 123或服务端allow列表没包含客户端网段检查iptables/nftables规则在chrony.conf里补充对应的allow行外部扫描还能看到monlist响应ntpd版本太旧或没有启用disable monitor升级到4.2.8p16以上并在配置里显式加入disable monitor设置限制后客户端频繁收到KOD包restrict default kod加上严格的频率限制导致正常客户端也被限制把kod从restrict参数里移除或者调整防火墙限速窗口和hitcount公网访问被拒但内网正常chrony只监听了内网地址或还有系统层防火墙拦住了来源如果需要对外服务先确认是可接受的业务需求再按需放行特定来源服务器流量突然飙升但本机看不到大量连接UDP反射流量可能只是过境流量不是发往本机端口123的连接用tcpdump抓包分析目的端口和源端口如果目的端口为123且来源IP混杂可能是攻击者在利用你作为反射源chrony服务重启后配置没生效配置文件路径不对或chronyd没有完全重启用systemctl restart chronyd然后用chronyc sources -v验证6.2 几个我踩过的坑第一只改服务端配置忘了同步系统防火墙。有一段时间我帮一个团队加固NTP把chrony.conf的allow收窄到了内网但服务器自带的ufw里UDP 123仍然是对所有来源放行的。服务端配置挡掉了大部分控制查询但端口本身还是裸的攻击者依然能发送大量UDP 123报文消耗CPU。正确做法是服务端和防火墙一起收紧哪怕服务端拒绝处理网络层的报文仍然会先进入主机影响性能。第二ratelimit设置太激进导致业务同步异常。chrony的ratelimit interval 4 burst 8对大多数场景够用但如果客户端数量特别多或者有些客户端配置了很短的同步周期可能造成同步请求被丢包。后来我把burst调到了16问题解决。限速的目的是抑制反射不是让正常业务不可用所以调整参数时一定要盯着客户端同步日志。第三IPv6漏配。很多服务器对外提供了IPv6地址但配置里只处理了IPv4。ntpd的restrict -6 default kod notrap nomodify nopeer noquery这行不能省否则攻击者可以通过IPv6路径绕过IPv4的限制。chrony也要记得在allow里配置IPv6子网或者直接在外层防火墙丢弃来源不明的IPv6 UDP 123包。6.3 写在最后的个人习惯我个人的一个习惯是所有NTP相关变更都会先用一台非生产机器压一遍配置确认服务正常后再应用到生产。NTP这个问题看着小出一件事就是全网拥塞级的。另一个习惯是定期抓包检查端口123不用多每月抓一次就行。当你能快速区分“正常同步”和“反射探测”的时候这台服务器基本就很难再被人拿去当放大器用了。
阅读完成 · 觉得有帮助?
咨询建站