Website Security Solutions | Blog

If you’re reading this article, you’re probably frustrated by the lack of relevant information about Squid, a very popular forward proxy. Some of these frustrations involve major usability changes occurring after minor software revisions, misconceptions about what’s actually happening behind-the-scenes, and genuinely poor documentation. This aims to be a comprehensive primer which will get you up and running with Squid.

First though, why might you want to use a forward proxy? Back in the day, it used to be very popular to terminate all outgoing connections at a proxy before sending them out to the internet. This is no longer as popular in the enterprise, but is something you might still run into on occasion. Squid however, can do much more than intercept plain-text communications – it can decrypt SSL/TLS communications on-the-fly as well in a couple of different configurations which have respective security implications.

There are two subtypes of forward proxies – explicit and implicit, and two ways to proxy SSL/TLS communication – terminating and non-terminating. Any of the four combinations are possible, and each has their own set of requirements. Explicit v. Implicit simply refers to whether the client has to specify (and possibly authenticate to) the forward proxy on their end. In this situation the client is aware that this is happening. It uses CONNECT messages to interface with the proxy and help it negotiate a connection to the destination.

Implicit connections on the other hand are a little bit trickier, and a lot more dangerous. In this configuration, the proxy is performing what in another context would be considered a man-in-the-middle attack. The client is completely unaware that somewhere their traffic is being sent is posing as the destination, decrypting their communication, and re-encrypting it to send to the real target server. Responses are captured on-the-fly as well, and sent back to the origin server. As we know, SSL/TLS prevents man-in-the-middle attacks twofold – by using asymmetric cryptography to secure communication with a private key and by maintaining a registry of trusted public keys. Implicit forward proxies bypass both of these protections (though often intentionally, and sometimes even securely). Instead of explicitly specifying the connection, the client simply sends off its traffic as it usually would. Somewhere upstream, the traffic is literally routed by a layer 3 device to the proxy, which then NATs the traffic to another interface in order to be able to avoid detection on the other end. It presents a certificate valid for any domain that it generates as requests hit it in real time, and because the client needs to be configured to trust the same root CA certificate the proxy uses, will allow the connection. (Remember, any certificate trusted as a root certificate can sign valid certificates for any and all domains and paths, not just its own.)

This configuration is incredibly useful however. Because the proxy terminates the connection and re-negotiates with the destination, it can actually change the kind of encryption used in-flight. Say you have older software that uses Java 6. You can put the Squid proxy in front of this server to allow it to achieve PCI compliance, as even though the software can only communicate via either plain old HTTP or HTTPS using TLS v1 (currently non-compliant), the proxy will re-encrypt the traffic using the TLS 1.2 gold standard.

How does one configure such a configuration? Well, it can certainly be a little bit of a hassle. It’s also different for every Operating System, but the basics are the same. This is not for the faint of heart, some experience compiling software in Linux is required.

As of this writing, the best version to use is Squid 3.5. Download it from the project website and unzip it to a directory. You will need gcc, make, and potentially other development environment tools for your linux distribution. On ubuntu in particular, installing build-essential should cover you. You’ll need two NICs on this box so that you can NAT between them.

You’ll want to create a user, named aptly: squid.

adduser squid

Make sure to use these flags to correctly link to libraries you will need.

./configure
        --prefix=/usr
        --exec-prefix=/usr
        --includedir=/usr/include
        --datadir=/usr/share
        --libdir=/usr/lib64
        --libexecdir=/usr/lib64/squid
        --localstatedir=/var
        --sysconfdir=/etc/squid
        --sharedstatedir=/var/lib
        --with-logdir=/var/log/squid
        --with-pidfile=/var/run/squid.pid
        --with-default-user=squid
        --enable-silent-rules
        --enable-dependency-tracking
        --with-openssl
        --enable-icmp
        --enable-delay-pools
        --enable-useragent-log
        --enable-esi
        --enable-follow-x-forwarded-for
        --enable-auth
        --enable-ssl-crtd
        --disable-arch-native
        --with-openssl

Follow with make, and then make install.

You’ll need to generate your own CA.

cd /etc/squid
mkdir ssl_cert
chown squid:squid ssl_cert
chmod 600 ssl_cert
cd ssl_cert
openssl req -new -newkey rsa:2048 -sha256 -days 365 -nodes -x509 -keyout myCA.pem  -out myCA.pem

You might determine that your CA should be valid for longer than 1 year.

openssl x509 -in myCA.pem -outform DER -out myCA.der

You will need to set the UID bit on the squid helper application “pinger”.

chown root:root /usr/lib64/squid/pinger

Your squid.conf should look something like this:

#
# Recommended minimum configuration:
#

# Example rule allowing access from your local networks.
# Adapt to list your (internal) IP networks from where browsing
# should be allowed
acl localnet src 10.0.0.0/8 # RFC1918 possible internal network
acl localnet src 172.16.0.0/12  # RFC1918 possible internal network
acl localnet src 192.168.0.0/16 # RFC1918 possible internal network
acl localnet src fc00::/7       # RFC 4193 local private network range
acl localnet src fe80::/10      # RFC 4291 link-local (directly plugged) machines
acl localnet src 127.0.0.1

acl SSL_ports port 443
acl Safe_ports port 80      # http
acl Safe_ports port 21      # ftp
acl Safe_ports port 443     # https
acl Safe_ports port 70      # gopher
acl Safe_ports port 210     # wais
acl Safe_ports port 1025-65535  # unregistered ports
acl Safe_ports port 280     # http-mgmt
acl Safe_ports port 488     # gss-http
acl Safe_ports port 591     # filemaker
acl Safe_ports port 777     # multiling http
acl CONNECT method CONNECT

sslproxy_cert_error allow all
#disable this in production, it is dangerous but useful for testing
sslproxy_flags DONT_VERIFY_PEER
#
# Recommended minimum Access Permission configuration:
#
# Deny requests to certain unsafe ports
http_access deny !Safe_ports

# Deny CONNECT to other than secure SSL ports
http_access deny CONNECT !SSL_ports

# Only allow cachemgr access from localhost
http_access allow localhost manager
http_access deny manager

# We strongly recommend the following be uncommented to protect innocent
# web applications running on the proxy server who think the only
# one who can access services on "localhost" is a local user
#http_access deny to_localhost

#
# INSERT YOUR OWN RULE(S) HERE TO ALLOW ACCESS FROM YOUR CLIENTS
#

# Example rule allowing access from your local networks.
# Adapt localnet in the ACL section to list your (internal) IP networks
# from where browsing should be allowed
http_access allow localnet
http_access allow localhost

# And finally deny all other access to this proxy
http_access deny all

# Squid normally listens to port 3128
http_port 3128

# Uncomment and adjust the following to add a disk cache directory.
#cache_dir ufs /var/cache/squid 100 16 256

# Leave coredumps in the first cache dir
coredump_dir /var/cache/squid

http_port x.x.x.x:3129 ssl-bump  \
  cert=/etc/squid/ssl_cert/myCA.pem \
  generate-host-certificates=on dynamic_cert_mem_cache_size=4MB

#this is what generates certs on the fly. Point to the CA you generated above.

https_port x.x.x.x:3130 ssl-bump intercept \
  cert=/etc/squid/ssl_cert/myCA.pem \
  generate-host-certificates=on dynamic_cert_mem_cache_size=4MB

acl step1 at_step SslBump1

ssl_bump peek step1
ssl_bump stare all
ssl_bump bump all
always_direct allow all

#
# Add any of your own refresh_pattern entries above these.
#
refresh_pattern ^ftp:       1440    20% 10080
refresh_pattern ^gopher:    1440    0%  1440
refresh_pattern -i (/cgi-bin/|\?) 0 0%  0
refresh_pattern .       0   20% 4320

Start the squid service with the command your operating system supplies. Make sure there are no errors in /var/log/squid

You can use the command:

sudo netstat -peant | grep ":3130"

to make sure that squid has successfully bound to the port.

This command will need to be applied at each boot to NAT traffic destined for port 443 on the IP traffic will be routed to (either using a static route on your origin device – y.y.y.y or on a network component) to the port squid is listening on on the other NIC bound to squid (x.x.x.x)

iptables -t nat -I PREROUTING -p tcp --dport y.y.y.y:443 -j DNAT --to x.x.x.x:3130

Assuming the client trusts the root certificate, the squid proxy will transparently proxy all connections destined outbound.


Author: Jeremy Schatten
Last Modified: 25/09/2018

    Next Guide...
    Using Client-Certificate based authentication with NGINX on Ubuntu

    An authenticated SSL/TLS reverse proxy is a powerful way to protect your application from attack. Both users and bad actors first connect to the proxy (which should live in your organization’s DMZ) and need to provide some form of authentication before the proxy even initiates a session with the b…