Hardened Network Time Protocol

May. 20, 2024 [hardening] [privacy-security] [guides] [libre] [technology]

Many contemporary devices still use the original network time protocol devised as it was in the 1980s. It is completely unencrypted and susceptible to time attacks. Disabling or removing the NTP daemon from a system does not workaround the issue since accurate system time is critical to cryptographic functionality.

Luckily, there are projects that seek to address this issue. One being ntpsec, a reimagining of the NTP client into a modernized and encrypted solution. As of Debian Bookworm, ntpsec is now the default time server (but only if you elect to install a time server), replacing the old ntp.

ntpsec can be installed through apt. A system daemon will be automatically added and, at least in Debian, automatically disables systemd’s timesyncd. But just in case your distribution does not do this, disable (or remove) existing NTP services.

systemctl disable systemd-timesyncd.service

Just installing ntpsec is not enough to have secured NTP. Even though ntpsec code drops some legacy cruft to reduce attack surface, we still need to point it at time servers which actually support NTS encryption. First, allow port 4460 outbound on your firewall (assuming nftables) for NTS key negotiation:

nft add rule inet fw fw-output tcp dport 4460 accept comment "\NTS\"

Then replace the default timeservers in /etc/ntpsec/npt.conf to comment out entries for Debian’s timepool:

#pool 0.debian.pool.ntp.org iburst
#pool 1.debian.pool.ntp.org iburst
#pool 2.debian.pool.ntp.org iburst
#pool 3.debian.pool.ntp.org iburst

There are not currently very many time servers supporting NTS, some of them can be found in the ntpsec documentation. Add at least three:

server ntpmon.dcs1.biz nts iburst
server ntp1.glypnod.com nts iburst
server ntp2.glypnod.com nts iburst

It is very important to include the parameter “nts”. “iburst” instructs the daemon how to query the time servers when first starting up.

Tie things off neatly by restarting ntpsec to apply the new settings:

systemctl restart ntpsec

You can test to confirm whether system time is now pulling from the new timeservers with some utilities:

ntpq -p

Output:

    remote                                   refid      st t when poll reach   delay   offset   jitter
======================================================================================================
+<domain>                               <ip address>     2 8  296 1024  377  84.7702  -1.4467   0.9012
+<domain>                               <ip address>     2 8  464 1024  377  83.5904  -1.2271   0.2856
*<domain>                               .PPS.            1 8  689 1024  305  92.4504   1.6698   1.5045
+<domain>                               <ip address>     2 8  665 1024  327  87.0531   0.6623   2.4672

“*” indicates the selected primary server based on performance criteria. The field “st” should be two or less on successful negotiation. Field “t” indicates whether cookie is held, it should be 8. The same information can also be viewed in realtime with the ntpmon textmode viewer.

You can probably also safely purge systemd-timesyncd once everything is confirmed working.

Understand that while ntpsec successfully encrypts NTP and avoids some security issues inherent with legacy NTP, not very many people run it as of this writing. And even though your time information is concealed between you and the timeservers, this configuration could make your overall network fingerprint more unique when running through proxies like a VPN. It may survive being placed behind Tor, as ntpsec had done just fine adjusting offsets when negotiating over a satellite link.

Additional mitigations against leaking host time information to be detailed in kernel and operating system hardening.