Project

General

Profile

Actions

Bug #14390

open

Squid: SECURITY ALERT: Host header forgery detected

Added by Simon Byrnand 12 months ago. Updated 7 months ago.

Status:
New
Priority:
High
Assignee:
-
Category:
Squid
Target version:
-
Start date:
Due date:
% Done:

0%

Estimated time:
Plus Target Version:
Affected Version:
2.6.0
Affected Plus Version:
Affected Architecture:

Description

In Squid version 3.2 in 2012 a "fix" for a potential security vulnerability involving host header forgery was added, this is described briefly here:

https://wiki.squid-cache.org/KnowledgeBase/HostHeaderForgery

It is also mentioned in the documentation for the host_verify_strict squid option below, which references CVE-2009-0801:

http://www.squid-cache.org/Doc/config/host_verify_strict/

In essence, when transparent interception is used Squid will obtain the SNI for https or host header for http, do a DNS lookup on this hostname enumerating the IP addresses returned, then double check the destination IP address of the intercepted packet is one of those returned from the DNS request.

If it's not, the request fails and returns an HTTP/409 error to the client, which shows up as a "NONE/409" in the squid access.log.

While this extra check is well intentioned, probably seemed like the right thing to do in 2012 and no doubt does address CVE-2009-0801, today in 2023 it has massive collateral damage and makes transparent proxying almost unusable for many large services that use CDN's, as it causes frequent but intermittent connection failures for many CDN based services.

The issue here is one of DNS coherency. As I've discovered when looking into this in detail in the last week CDN service DNS records have extremely short TTL times of around 10 or 20 seconds typically. After that TTL expires you will more often than not get a completely disjoint set of different IP addresses returned than what you got just 20-30 seconds earlier.

A couple of examples I'm working with which can be queried multiple times over a couple of minutes with dig returning different results are:

res.cdn.office.net
uk.ng.msg.teams.microsoft.com

These are both used by Office 365 / Microsoft Teams, however this issue of very short TTL times and disjointed IP address response sets seems to be pervasive in large CDN infrastructure as of 2023.

The end result is intermittent http/https query failures returning HTTP/409. In my testing in the last few days Microsoft Teams on iOS is very susceptible to this problem and is basically unusable as it will work for a while then just fail to connect to the servers or be able to start a video call due to Squid returning HTTP/409 errors to it.

Ensuring DNS coherency between clients and proxy server (by forcing clients and proxy server to use the same DNS server - which I already do) does help on regular websites with long TTL's, or websites whose IP address result set is consistent, and is essential to getting transparent proxying working, however it does not help this issue with CDN's. :(

Here is what I think is happening in the specific instance of the Teams client, however the same basic scenario can apply to other client software as well.

The Teams app performs a DNS lookup on uk.ng.msg.teams.microsoft.com and gets multiple IP addresses returned. It chooses one and makes an https query to the server using this IP address. Squid intercepts this transparently, reads the SNI, does its own DNS lookup from the same DNS server, gets the same response, verifies that the IP address of the destination packets match the DNS records and everything works fine.

A couple of minutes later Teams makes a new https request to the same hostname using an internally cached (within the application) copy of the IP address - Squid performs another DNS lookup on the hostname as the extremely short TTL has already expired, however this time the IP addresses returned are completely different so the request fails with an HTTP/409 error. This breaks the client.

TTL on DNS records only mandates how long a DNS server or OS level resolver can cache the result for, it cannot prevent an application choosing to continue to use the same IP address for longer than the TTL. It would be perfectly reasonable for an HTTPS connection to stay open for an hour for example even if the DNS record has a TTL of 10 seconds. Absent the transparent proxy there is no issue because the server IP's remain valid for long periods of time (probably days/weeks) even though the DNS records are constantly rotating every 10-60 seconds or so.

From my perspective, the transparent mode is mostly useless now due to the combination of this original 2012 patch (which to be fair is a Squid patch not anything specific to PFSense) and the ubiquitous use of CDN's with extremely low DNS record TTL's and disjoint result sets that are constantly cycling IP addresses in and out of the results.

This issue has been discussed in the PFSense forum before:

https://forum.netgate.com/topic/159364/squid-squidguard-none-409-and-dns-issue

However the only outcomes were workarounds such as explicit client proxy settings or use of WPAD, both of which only admit that transparent proxying is broken. I make use of both of these where possible but there are still many cases where this is not possible.

The only true solution to get transparent mode working reliably again seems to be to walk back the "fix" applied back in Squid 3.2 and accept that theoretical exploit could be used, however without doing so we basically have to give up on transparent proxying altogether.

Patching this out has been discussed in a couple of places that I've found, here is one:

https://github.com/NethServer/dev/issues/5348

To reproduce and monitor this issue is fairly easy:

Set up Squid in PFSense with transparent proxying enabled. Enable additional debug logging by adding debug_options ALL,1 rotate=7 to Advanced Features -> Custom Options (Before Auth) then try using apps such as Microsoft Office apps that make heavy use of CDN's, making sure that the client has no proxy setting.

In /var/squid/logs/cache.log if the problem occurs you will see entries like:


2023/05/16 10:16:08 kid1| SECURITY ALERT: Host header forgery detected on local=3.227.250.226:443 remote=10.2.132.38:50635 FD 526 flags=33 (local IP does not match any domain IP)
2023/05/16 10:16:08 kid1| SECURITY ALERT: on URL: kinesis.us-east-1.amazonaws.com:443
2023/05/16 10:16:08 kid1| SECURITY ALERT: Host header forgery detected on local=3.227.250.226:443 remote=10.2.132.38:50636 FD 526 flags=33 (local IP does not match any domain IP)
2023/05/16 10:16:08 kid1| SECURITY ALERT: on URL: kinesis.us-east-1.amazonaws.com:443
2023/05/16 10:16:09 kid1| SECURITY ALERT: Host header forgery detected on local=17.253.29.208:443 remote=10.2.133.96:62179 FD 526 flags=33 (local IP does not match any domain IP)
2023/05/16 10:16:09 kid1| SECURITY ALERT: on URL: app-site-association.cdn-apple.com:443
2023/05/16 10:16:09 kid1| SECURITY ALERT: Host header forgery detected on local=3.227.250.226:443 remote=10.2.132.38:50637 FD 526 flags=33 (local IP does not match any domain IP)
2023/05/16 10:16:09 kid1| SECURITY ALERT: on URL: kinesis.us-east-1.amazonaws.com:443

These log entries show both the host name that was requested by the client and the "local" IP address that the client was trying to connect to, if you do multiple DNS lookups of the hostname over a couple of minutes you will find that sometimes it returns the IP address, sometimes it does not.

While I appreciate this issue is an upstream issue I think it very unlikely that the Squid maintainers would accept a patch to walk back the change that was made in 2012, however I would argue that the transparent mode is barely usable due to this issue, so hopefully you would consider a patch to address this.

Regards,
Simon


Files

Transparent Proxy test.py (1.67 KB) Transparent Proxy test.py Python script Simon Byrnand, 05/17/2023 10:18 AM

Related issues

Has duplicate Feature #14786: Add GUI option for host_verify_strictDuplicate

Actions
Actions

Also available in: Atom PDF