NGINX Cache Poisoning Vulnerability - OK to Use Linode's DNS Resolvers?
I'm concerned about potential NGINX security vulnerabilities as detailed in this blog post. While the author has recommended against using any DNS resolver on the Internet for NGINX's resolver
directive, is it OK to use Linode's resolvers?
2 Replies
While I'm not able to vet the author's work or assess if NGINX's replies on the email chain in the linked blog are sufficient answers to their concerns, this problem seems to be with NGINX rather than any particular resolver. Presumably, if the issue is that using any public DNS resolver cannot be trusted for use with NGINX for purposes, then that would include Linode's. The question would then become if you, the admin, decide if the author's concerns are valid enough for you to consider setting up DNS on your Linode.
If one is sufficiently worried, it looks like you might be able to use systemd-resolved
as a local intermediary between NGINX and public DNS resolvers, such as Linode's. systemd-resolved
listens on 127.0.0.53
by default, and appears to be setup out of the box on Ubuntu (18.04, at least).
That blog was a pretty interesting read. Anyone else have some thoughts on this?
If Linode applies reverse path filtering at the transit provider interface, assuring that no traffic claiming to be from a Linode IP can come from a transit provider, then using Linode's resolvers is not an issue, as the only people who can spoof traffic to claim to originate from a Linode resolver in that situation would be Linode themselves.
Even if Linode doesn't do reverse path filtering, the likelihood of an attacker succeeding is extremely low, given all the information they need to know and have to guess.
Here's the list:
- name being looked up (must be known, could be leaked)
- resolver being used (could be guessed, as the list of Linode resolvers for a datacenter is public, ~20 possibilities)
- DNS query ID (called txid in the post, must be guessed, 65536 possibilities)
- UDP source port for the query (must be guessed, probably 28232 possibilities)
Putting it all together, there are 37,004,247,040 (37 billion) possible combinations. Assuming 1,000 spoofed packets per lookup with a 1 hour TTL, averaging it out, and rounding, they might manage to poison the response 2,000 years from now.
The most common situation where resolver is used in nginx is OCSP stapling. In this situation, the name is known to the attacker already, because it's in the certificate. However, nginx validates OCSP responses prior to returning them to clients, and while I haven't looked deeply into it, I would imagine it simply stops sending the stapled OCSP response to the client when the one it has has expired and it can't retrieve a valid new one (this would cause issues with OCSP Must Staple certificates, but I imagine the client also validates the stapled response as well, so an expired response would equally fail).
I would suspect that most people that use Linode and run nginx don't use names in *_pass directives, so they would not even be vulnerable to the issues described in the link. If they were, the above assessment still applies.
Since I'm sure somebody would ask otherwise, I'll explain why the DNS query ID must be guessed, instead of using the attack described in the link. Almost nobody uses nginx for reverse proxying mail protocols; their mailservers just listen on the public IP address directly. Nobody uses nginx without the SSL module (well, somebody might, but they're very very rare, as they would have had to compile nginx themselves, and they're unlikely to use $request_id
in a header). So the only usage of random() is for the DNS query ID, and thus the prediction cannot be used. If the nginx version you have still has issue 5, the time can probably be shrunk quite a bit by trying to guess the PRNG seed, which has limited values, and then trying to guess where it is in the sequence, but it's still not a feasible attack.
If after reading this, you're still concerned, just set up a local resolver.