Package: httpsdate
httpsdate.pyThis is a (fairly) simple python script that sets the system clock to a value obtained from a set of HTTPS servers.
This provides a simple and secure, but not very accurate method of time synchronisation.Why?Several of today's security technologies assume a correct local clock.
One example is certificate expiration.Unfortunately, the choice of secure and reliable clock synchronisation protocols is scarce.
A discussion of the sorry state of today's options can be found inhttps://blog.hboeck.de/archives/890-In-Search-of-a-Secure-Time-Source.htmlby @hannob.
The author also came up with a simple, yet effective method of securely synchronising the system clock with a remote server.This method and the scripthttpstimeare what inspiredhttpsdate.py.
It was written to overcome some of the limitations imposed by the simplistic design ofhttpstime:httpsdate.pyautomatically runs with minimal privileges.httpsdate.pydoes not necessarily rely on a single server to provide the correct time.How does it work?httpsdate.pyqueries one or more HTTPS servers for the timestamp in theDateHTTP header.
The system clock is then set to the median of the timestamps obtained this way.As long as more than half of the timestamps are correct, the resulting system time is correct.
It may however, loose a few seconds of accuracy, due to the limitations imposed by the very simplistic protocol.httpsdate.pyexits when it is done.
To keep the system clock in sync over a extended period of time, simply runhttpsdate.pyregularly, for example as a cron job or systemd timer.How to use itThe most simple way to use it is to run something like the following command asroot:httpsdate.pywww.ptb.deThis will get the current time fromwww.ptb.deand set the local system clock to match it.
The console output looks something like this:Time adjustment: 0.43 seconds
1 remote clocks returned usable time information, 0 did not.As mentioned above, it is also possible to query multiple servers:httpsdate.pywww.ptb.dewww.metas.chSee [below](#Rogue Servers) on why one would want to do that.Before explaining the other options ofhttpsdate.py, let's have a look at the help message:usage: httpsdate.py [-h] [-n] [-u USER] [--max-adjust seconds] [-q]
                    host [host ...]

Set the system clock to a date and time obtained from one or more HTTPS
servers. Needs to be run with CAP_SYS_TIME, but drops unnecessary privileges
when started as root.

positional arguments:
  host                  get the time from the Date header of these HTTPS
                        servers

optional arguments:
  -h, --help            show this help message and exit
  -n, --dry-run         do not actually set the system clock
  -u USER, --user USER  when started with high privileges, run as this user
                        instead (default: nobody)
  -t seconds, --timeout seconds
                        HTTPS network response timeout (default: 3 seconds)
  --max-adjust seconds  do not change the clock more than this many seconds
  --max-failed N        do not change the clock if more than N servers failed
                        to send a usable date and time
  -q, --quiet           do not show warnings and adjustment informationIfhttpsdate.pyis invoked withrootprivileges, it will automatically drop all privileges exceptCAP_SYS_TIME(which is required for setting the system clock) and switch to a non-privileged user.
Use--userto specify what user account to switch to.It is not necessary to runhttpsdate.pyasroot.
Running it with onlyCAP_SYS_TIMEis sufficient.
Without further privileges, it can obviously not switch the user and silently ignores the--useroption, if provided.Use--dry-runin order to just see what would happen but not actually change the system clock.When invoked with--quiet,httpsdate.pysuppresses non-error messages.
Non-error messages are:warnings about unusable servers, e.g. due to certificate validation errorsthe summary at the end, which can help estimating the reliability of the new system timeUsually, the system time can be trusted to be not too far off from the correct time.
To reflect that, the option--max-adjustcan be used.
It instructshttpsdate.pyto bail out without modifying the system clock if the new time is too far from the current system time.
Together with infrequent synchronisations, this helps prevent malicious servers from deliberately changing the system clock (much).
Reasonable values are a few minutes or seconds, depending on the usual clock drift and the synchronisation frequency.Similarly,--max-failedlimits the fault tolerance ofhttpsdate.py.
It will not change the system clock if more than this many remote servers failed to send a usable time.
Reasons for not getting a usable time include invalid X.509 certificates, TLS parameter incompatibilities or missing or invalidDateheaders.For better accuracy control,--timeoutcan be used to change the HTTPS network timeout for the connections to the remote servers.
Remote servers that do not respond within the time limit are simply skipped and count as failed.
This can help reducing the delay between obtaining the remote time and actually changing the system clock.RequirementsLinux Kernel 3.5 or newerPython 3.4.3 or newerpython-prctla moderately correct system time to begin with (a few months off should be OK)httpsdate.pyshould also run on Python 3.3.
Before 3.4.3 Python did not validate HTTPS certificates by default, thus rendering HTTPS vulnerable to man-in-the-middle attacks, unless the respective code sets up validation.httpsdate.pyrelies on Python do the right thing and should therefore not be used with Python versions before 3.4.3 (unless they are patched, that is).In case of doubt, one can runhttpsdate.py-nself-signed.badssl.comorpython3-c'from urllib.request import urlopen; urlopen("https://self-signed.badssl.com")'If either command throws an error containingCERTIFICATE_VERIFY_FAILED, all is well and Pythondoesvalidate certificates.InstallationNo installation is required.
It is enough to download and runhttpsdate.py.For convenience,httpsdate.pycan also be installed usingpip:pipinstallhttpsdateSecurity ConsiderationsMan-in-the-Middle attackshttpsdate.pyvalidates the X.509 certificates of the remote servers.
This effectively authenticates the time information using the X.509 PKI system.
Therefore, a man-in-the-middle attacker can not deliberately set an incorrect time without breaking the TLS connection(s).The attacker can, however, drop the connections, thus preventing time synchronisation.Rogue ServersBy setting the system clock to a value obtained from a remote server, one trusts the remote server's administrator to keep their time correct (and reasonably accurate).In order to reduce the amount of trust that needs to be put in each remote server,httpsdate.pycan use multiple servers.
If more than half of the remote servers that provide a usable time also provide a correct time, the use of the median ensures that the selected time is bounded by correct time values.
Therefore, a single rogue server can not influence the resulting system time (as long as at least two other servers respond, that is).Man-in-the-Middle and Rogue ServersA man-in-the-middle attacker who also controls (at least) one of the queried servers can easily drop connections to the servers they do not control and therefore force a single usable time value.Using the parameter--max-failedprovides some protection in this scenario as the acceptable number of failed remote servers - e.g. due to dropped connections - can be limited.
This effectively raises the number of servers that need to be under the control of the attacker.
Still, more than half of the responses need to be correct to ensure that the system clock is set to a correct time.Software Bugshttpsdate.pydepends on other software.
For instance, is written in python and runs on the Linux kernel.
Bugs in the python interpreter and the Linux kernel may therefore affecthttpsdate.py.httpsdate.pymay have bugs of its own.For this reason,httpsdate.pyattempts adhering to the principle of least privilege.
Setting the system clock on Linux requires elevated privileges, but not fullrootprivileges.httpsdate.pyworks well with only the capabilityCAP_SYS_TIME, which is required to set the clock.
If it is started with fullrootprivileges, which is often more convenient than employing fine-grained capability control, it drops all unnecessary privileges and runs with the user and group id of an unprivileged user.
This is, of course, done before connecting to the network.There are, however, further security measures thathttpsdate.pydoes not currently employ itself, such as namespaces and seccomp filters.
It should be possible to usehttpsdate.pytogether with these technologies, if they are not configured too restrictive.
To runhttpsdate.pyin a restricted sandbox, one can use systemd, bubblewrap or firejail, for instance.httpsdate.pyitself is FOSS and fairly short and simple code.
It actually has fewer raw lines than this readme.
The code can be audited independently to increase the confidence that it does not exhibit any undesirable behaviour.Considerations on AccuracyAs mentioned earlier, the accuracy ofhttpsdate.pyis not very high.
"Not very high" means that is should usually be within a few seconds of the reference time.
This is not ideal, but good enough for most purposes.There are three factors that influence the accuracy and that can, to some extent, be taken into account in order to get better results.Resolutionhttpsdate.pyretrieves the remote time from theDateHTTP header, which only has a resolution of one second.
Hence, sub-second accuracy is simply not achievable with this approach.Network DelaysThe time, as set by the remote server, takes some time to reachhttpsdate.py, which then takes a few more CPU cycles before the system clock is set.httpsdate.pydoes not do anything clever to correct these delays or even measure the amount of error.
This simply has not been given consideration and likely never will be.
Any attempts may turn out to be infeasible due to the limited resolution of the obtained time data.The usual methods for reducing network delays apply, e.g. picking servers that have quick response times.Remote Clock AccuracyTheDateheader is not intended for communicating accurate, current time information.
Therefore, administrators of HTTPS servers may not keep their own clock very accurate.
Moreover, caching (reverse) proxy servers and similar network components may result in staleDateheaders being returned by remote servers.While it is possible to usehttpsdate.pywith any modern HTTPS-capable web server, it does make sense to pick servers that are expected to keep their own clocks as accurate as possible and always generate fresh headers.LicenseMIT