Authenticating a Proxy server over HTTPS
As is customary, let's first answer the exact question which was asked.
Right now, using HTTPS to connect to the proxy is not widely supported. The squid documentation has some information on the subject; to sum things up:
Chrome supports it, but it must be configured through a proxy auto-configuration script because there is no GUI support. This also means not using the "system-wide proxy configuration".
Firefox does not support it, although the feature has been marked as requested since 2007. (UPDATE: Supported in FF 33+)
No indication on other browsers, which can be surmised to mean "no support whatsoever".
What Chrome does when encountering a "somewhat invalid" certificate for the proxy should be tested, but it is likely to depend on the exact browser version (which changes all the time, often transparently), the operating system (since certificate handling tends to be delegated to the OS), and in what ways the certificate is not valid (expired, bad server name, unknown trust anchor,...). Also, there is an inherent chicken-and-egg issue here: full certificate validation, as is mandated by X.509, includes checking revocation, i.e. download of CRL for all certificates in the path. URL for CRL download are usually located in the certificates themselves. But if you are using a proxy for your HTTP traffic, then the CRL download will need to go through that proxy... and you have not yet validated the proxy certificate. No chicken, no egg.
We may also note that the proxy auto-configuration file format does not really support HTTPS proxying. There is no formal standard for this file, but custom is to follow an old Netscape draft which says that a PAC file defines a Javascript function which can return proxy hostnames and ports, but not protocol. So, no HTTPS. For its HTTPS-proxy support, Chrome implicitly uses an extension to this de facto convention by stuffing an HTTPS URL where it has no right to be, and hoping for the browser to make some sense out of it.
As is customary, let's see what alternate proposals can be made.
To ensure protected communication between the client and the proxy, the two following solutions may be applicable:
Use a VPN. This is highly generic, and since it operates at OS level, it will apply to all browsers. Of course, it requires that whoever installs the thing on the client machine has administrative rights on that machine (you cannot do this as a simple unprivileged user).
Use a SSH-based SOCKS proxy. On your client system, run:
ssh -N -D 5000 theproxy
; then set your browser to uselocalhost:5000
as SOCKS proxy. This solution requires that you have the proxy server (theproxy
) is also a SSH server, and that you have an account on it, and that the SSH port is not blocked by some ill-tempered firewall.
The SOCKS proxy solution will ensure that the traffic goes through the proxy machine, but does not include caching, which is one of the reasons we usually want to use a proxy in the first place. It can be altered by using some additional tools, though. SOCKS proxying is about redirecting all TCP/IP traffic (generically) through a custom tunnel. Generic support for applications is possible, by "replacing" the normal OS-level network calls with versions which use SOCKS. In practice, this uses a specific DLL which is pushed over the standard OS libraries; this is supported in Unix-based systems with LD_PRELOAD
, and I suppose this can be done with Windows too. So the complete solution would be:
- You use a SSH-based SOCKS tunnel from your client to the proxy machine.
- The SOCKS client DLL is applied on the browser, and configured to use
localhost:5000
as SOCKS proxy. - The browser just wants to use
theproxy:3128
as plain HTTP proxy.
Then, when the browser wants to browse, it opens a connection to theproxy:3128
, which the DLL intercepts and redirects to a SOCKS tunnel that it opens to localhost:5000
. At that point, SSH grabs the data and sends it to theproxy
under the protection of the SSH tunnel. The data exits on theproxy
, at which point the connection to port 3128 is purely local (thus immune from network-based attackers).
Another way to add caching on the SSH-SOCKS setup is to apply a transparent proxy. Squid can do that (under the name "interception caching").
Yet another way to do caching with SSH protection is to use SSH to build a generic tunnel from your machine to the proxy. Run this:
ssh -N -L 5000:localhost:3128 theproxy
and then set your browser to use localhost:5000
as an HTTP proxy (not SOCKS). This will not apply proxying on alternate protocols such as FTP or Gopher, but who uses them anyway ?
As is customary, let's now question the question.
You say that you want to protect against a man-in-the-middle attack. But, really, the proxy is a MitM. What you really want is that the proxy is the only entity doing a MitM. HTTPS between the browser and the proxy (or SSH-SOCKS or a VPN) can protect only the link between the client and the proxy, and not at all between the proxy and the target Web server. It would be presumptuous to claim that MitM attacks are reliably thwarted without taking into account what happens on the Wide Internet, which is known to be a harsh place.
For end-to-end protection against MitM, use SSL, i.e. browse HTTPS Web servers. But if you do that, then extra protection for the browser-to-proxy link is superfluous.
Protecting traffic between browser and proxy makes sense if you consider proxy authentication. Some proxies require explicit authentication before granting access to their services; this is (was ?) common in big organizations, which wanted to reserve "unlimited Internet access" to some happy few (usually, the Boss and his favourite underlings). If you send a password to the proxy, then you do not want the password to be spied upon, hence SSL. However, an attacker who can eavesdrop on the local network necessarily controls one local machine with administrator privileges (possibly, a laptop he brought himself). His nuisance powers are already quite beyond simple leeching on the Internet bandwidth. Also, limiting Internet access on a per user basis maps rather poorly to modern operating systems, which tend to rely on Internet access for many tasks, including software updates. Internet access is more efficiently controlled on a per usage basis.
Therefore, I think that protecting access to a HTTP proxy has some merits, but only in rather uncommon scenarios. In particular, it has very little to do with defeating most MitM attacks.
Chrome on client side, and Squid on proxy side can work via https. See Secure Web Proxy for more details.
I hope that Chrome will warn you on invalid proxy certificate, but have no experience with this setup so can't confirm.