Filtragem avançada de HTTPS com Squid Proxy

Por Lucas Almeida Como Squid Proxy pode te ajudar a filtrar conteúdo e serviços web, aumentando a segurança de sua organização.

Big Data Brasil
Big Data Blog
9 min readSep 5, 2023

--

Mesmo em sistemas seguros que seguem todas as práticas de segurança, as pessoas que trabalham utilizando esses sistemas são propensas ao erro.

Como citado por Neil Daswani, co-diretor do Stanford’s Advanced Cybersecurity Program e autor do livro “Big Breaches: What We Learned From Some of the World’s Most Disruptive Cybersecurity Attacks”, “enquanto queremos confiar nos humanos para fazer a coisa certa tão frequentemente quando podem, temos que estar aptos a defender nossos sistemas mesmo quando eles erram” [1].

No contexto de redes corporativas, pode ser interessante bloquear ou limitar o acesso dos funcionários a determinados serviços web. A motivação por trás disso pode ser prevenção contra vazamentos de dados e instalação de pacotes maliciosos, garantindo um ambiente mais seguro.

Garantir a segurança dos dados dos clientes pode servir de cartão de visita de uma empresa, especialmente para aquelas que trabalham com grandes volumes de dados, como é o caso da Big Data.

Há ainda outras motivações, como prevenção contra vazamento de credenciais e bloqueio a sites indesejados, como redes sociais.

Objetivo e conceitos importantes

O objetivo deste artigo é construir “from scratch” uma configuração do Squid Proxy, servidor proxy popular e com diversos casos de uso, para filtragem de conteúdo web. O principal empecilho para isso é a presença de websites configurados com criptografia TLS/SSL (usada no protocolo HTTPS), que ao mesmo tempo que impedem ataques do tipo man-in-the-middle, também impedem esse tipo de filtro.

Man-in-the-middle é um tipo de configuração, comumente associada a um tipo de ataque cibernético, em que a comunicação de dois computadores é interceptada por um terceiro, no meio. Esse computador intermediário consegue ler qualquer dado que transite do cliente para o servidor e vice-versa, por isso é importante que os dados trafegados estejam criptografados. A motivação no uso de TLS/SSL é prevenir esse tipo de ataque.

A ideia é configurar o Squid Proxy para atuar como man-in-the-middle, interceptando as requisições criptografadas, descriptografando-as e fazendo um simples filtro com base na URL. Sem essa configuração, a filtragem estaria limitada a protocolos de camadas inferiores do modelo TCP/IP e a poucas informações disponíveis no estabelecimento da conexão. Como o TLS/SSL atua na camada de aplicação, informações das camadas de transporte e de rede não estão criptografadas, permitindo a leitura da porta e endereço IP destino.

Utilizaremos uma máquina com sistema operacional Amazon Linux 2023, com o pacote squid instalado na versão 5.8. Assume-se que todos os comandos listados neste artigo estão sendo executados com permissões de administrador.

Caso esteja utilizando outro sistema operacional ou versão do Squid, verifique com o seguinte comando se a versão é superior ou igual a 3.5 e se as opções –enable-ssl e –with-openssl estão habilitadas.

squid --version

Proxy direto vs proxy transparente

Temos duas opções de proxy para projetar nosso sistema. Essa decisão vai refletir na configuração de nossas máquinas cliente.

Um proxy direto é um proxy em que o cliente precisa configurar explicitamente que quer utilizá-lo. Já um proxy transparente é um proxy que atua na rede sem que o cliente saiba. O último pode ser habilitado através de tabelas NAT e roteamento.

Na configuração do Squid, podemos definir qual(is) proxy(ies) queremos utilizar. Caso queiramos por exemplo utilizar ambos, podemos fazer a seguinte configuração:

http_port 3128           # Proxy direto disponível na porta 3128
http_port 8080 intercept # Proxy transparente disponível na porta 8080

Para utilizar o proxy transparente, precisamos definir redirecionamentos NAT dentro da máquina que executará o Squid. A razão por trás disso é que o cliente não sabe que existe um proxy transparente no meio da conexão, resultando que as requisições sejam enviadas para as portas 80 ou 443 (HTTP e HTTPS, respectivamente). A ideia então é permitir que as requisições que chegam nessas portas sejam redirecionadas para as portas utilizadas na configuração do Squid.

Isso pode ser feito utilizando o pacote iptables-services, disponível no Amazon Linux 2023. Caso queira utilizar um proxy transparente, execute no shell os seguintes comandos:

systemctl start iptables
iptables -t nat -A PREROUTING -p tcp - dport 80 -j REDIRECT - to-port 8080
iptables -t nat -A PREROUTING -p tcp - dport 443 -j REDIRECT - to-port 8443
iptables-save -t nat > /etc/sysconfig/iptables
systemctl restart iptables
echo 1 > /proc/sys/net/ipv4/ip_forward
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf

A combinação desses comandos fazem com que pacotes destinados à porta 80 ou 443 que forem recebidos por esta máquina sejam encaminhados para a porta 8080 ou 8443, respectivamente.

Para que um proxy transparente funcione como desejado, é necessário configurar externamente uma tabela de roteamento dentro de uma rede privada, mas isso foge do escopo do artigo.

Configuração HTTP

A configuração do Squid em sistemas Linux é feita através do arquivo /etc/squid/squid.conf. É possível fazer chamadas a outros arquivos de configuração e algumas distribuições fazem isso na instalação do pacote. Na dúvida, edite diretamente o arquivo citado para garantir que a configuração está sendo feita “from scratch”. Em um ambiente de produção, é importante checar quais configurações são habilitadas por padrão a fim de prevenir falhas de segurança, de performance ou de monitoramento.

Nesta configuração utilizaremos proxy transparente. Como o pacote do Squid, na versão e no sistema operacional que estamos utilizando, força que definamos um proxy direto, bloquearemos as requisições recebidas por este tipo de proxy.

http_port 3128
http_port 8080 intercept

acl FORWARD_MODE_LOCALPORT localport 3128

acl SAFE_PORTS port 80
acl SAFE_URLS url_regex ^http://example\.com[/]?$

http_access deny !SAFE_PORTS
http_access deny FORWARD_MODE_LOCALPORT

http_access allow SAFE_URLS

http_access deny all

Observação: execute em seu terminal shell o comando “squid -k reconfigure” sempre que alterar o arquivo de configuração. Caso seja retornado um erro, execute “systemctl restart squid” e verifique o status do serviço utilizando o comando “systemctl status squid”.

Inicialmente, definimos dois proxies: um direto na porta 3128, e outro transparente na porta 8080.

Em seguida, em nossas ACLs, definimos FORWARD_MODE_LOCALPORT, que será utilizada para indicar as requisições que vierem pelo proxy direto.

Definimos também a ACL SAFE_PORTS, futuramente utilizada para bloquear requisições destinadas a portas inseguras, e a ACL SAFE_URLS, futuramente utilizada para liberar requisições destinadas a websites confiáveis. Em nossa configuração, apenas as URLs http://example.com e http://example.com/ são consideradas confiáveis.

Por fim, lidamos com a filtragem em si. Antes disso, é importante citar como o Squid lida com o controle de acesso: recebe uma requisição e lê regra por regra do arquivo de configuração, de cima para baixo, até encontrar uma regra cujas ACLs correspondam às características requisição.

Seguem 4 exemplos de requisição e como a configuração definida acima lidaria com cada uma delas:

  • Uma requisição HTTP é recebida, mas como seu destino é uma porta 443, é bloqueada pela primeira regra (caractere ! indica negação).
  • Uma requisição HTTP com destino a uma porta 80 é recebida, mas como ela veio através do proxy direto, é bloqueada pela segunda regra.
  • Uma requisição HTTP com destino a uma porta 80 é recebida através do proxy transparente, e como seu destino é a URL http://example.com, é liberada pela terceira regra.
  • Uma requisição HTTP com destino à URL http://example.com/endpoint na porta 80 é recebida através do proxy transparente, mas é bloqueada pela quarta regra.

É importante notar que all é um valor pré-definido pela configuração do Squid.

Geração de certificado CA

Antes de continuarmos com a configuração para HTTPS, vamos criar um conjunto chave e certificado Certificate Authority (CA).

Isso é importante pois o Squid estará atuando como man-in-the-middle, gerando duas conexões distintas: cliente com o Squid, e Squid com servidor destino. Isso faz do próprio Squid um servidor, que precisa gerar assinaturas aos clientes a fim de estabelecer uma conexão TLS/SSL.

Gere um conjunto chave e certificado CA com o seguinte comando, em um shell:

openssl req -new -newkey rsa:2048 -sha256 -days 365 -nodes -x509 -extensions 
v3_ca -keyout myCA.pem -out myCA.pem

Como se trata de um ambiente de desenvolvimento privado, não se preocupe com o preenchimento das informações solicitadas.

Abra o arquivo myCA.pem e copie para a área de transferência o certificado gerado, delimitado por BEGIN CERTIFICATE e END CERTIFICATE. Inclua essas duas linhas ao copiar.

Configure a máquina que fará acesso através da proxy para confiar neste certificado. No caso de um proxy direto, pode ser a própria máquina que está com o Squid instalado.

No Amazon Linux 2023, você pode confiar no certificado criando-o em /etc/pki/ca-trust/source/anchors/myCA.pem, e executando o comando:

update-ca-trust extract

Já no Ubuntu Server 22.04 e outras distribuições como Debian e Alpine Linux, crie em /usr/local/share/ca-certificates/myCA.crt e execute o comando:

update-ca-certificates

Por fim, na máquina que está executando o Squid, mova e renomeie o conjunto chave e certificado para /etc/squid/ssl/squid.pem, para fins de organização.

Observação: é possível utilizar uma chave CA raiz para assinar uma requisição de certificado do Squid. Assim, todas as máquinas que confiarem no CA raiz também confiarão no Squid como man-in-the-middle. Mas atenção: o certificado gerado também precisa ser um CA.

Configuração HTTPS

Nosso objetivo é atingir a mesma configuração que fizemos para HTTP, mas permitindo também HTTPS.

Para isso, podemos antes criar um banco para servir de cache dos certificados gerados usando nosso CA. Usando amazon Linux, basta executar o comando:

/usr/lib64/squid/security_file_certgen -c -s /var/lib/ssl_db -M 4MB

Neste comando, estamos executando um programa do Squid chamado security_file_certgen. A opção -c indica que estamos criando e inicializando o banco, enquanto as opções -s e -M indicam, respectivamente, em qual diretório o banco será criado e qual o tamanho máximo em disco a ser usado.

Para configurar um proxy transparente, podemos adicionar ao nosso arquivo squid.conf:

https_port 8443 ssl-bump intercept tls-cert=/etc/squid/ssl/squid.pem
dynamic_cert_mem_cache_size=4MB generate-host-certificates=on
sslcrtd_program /usr/lib64/squid/security_file_certgen -s /var/lib/ssl_db -M
4MB

Na primeira linha desta seção da configuração, definimos que o CA criado anteriormente (agora nomeado squid.pem) será usado para assinar as requisições. Ainda nessa linha, definimos o tamanho de cache que estamos utilizando e habilitamos a geração dinâmica dos certificados.

A linha seguinte define qual programa será utilizado para gerar os certificados dinamicamente. Perceba que agora não está mais definida a opção -c, já que o banco já foi criado anteriormente e só precisamos utilizá-lo. Para mais informações, passe a opção -h ao programa security_file_certgen.

Observação: A configuração de proxy direto é idêntica, porém com a remoção do modo intercept e utilizando http_port ao invés de https_port. Caso esteja utilizando proxy direto, lembre-se de liberar no firewall (security groups na AWS) a porta que estiver usando.

Segue a configuração completa:

http_port 3128

https_port 8443 ssl-bump intercept tls-cert=/etc/squid/ssl/squid.pem
dynamic_cert_mem_cache_size=4MB generate-host-certificates=on
sslcrtd_program /usr/lib64/squid/security_file_certgen -s /var/lib/ssl_db -M
4MB

http_port 8080 intercept

acl FORWARD_MODE_LOCALPORT localport 3128

acl HTTPS_PORT port 443
acl SAFE_PORTS port 80
acl SAFE_PORTS port 443
acl SAFE_URLS url_regex ^http[s]?://example\.com[/]?$

ssl_bump bump all

http_access deny !SAFE_PORTS
http_access deny CONNECT !HTTPS_PORT
http_access deny FORWARD_MODE_LOCALPORT

http_access allow CONNECT HTTPS_PORT
http_access allow SAFE_URLS

http_access deny all

Primeiramente, perceba que temos uma porta para receber requisições http e outra para receber requisições https. Também adicionamos a porta 443 à ACL SAFE_PORTS e alteramos a ACL SAFE_URLS para aceitar mais duas URLs: https://example.com e https://example.com/.

A configuração ssl_bump bump all é a configuração responsável por garantir que todos os pacotes https recebidos sejam descriptografados e criptografados pelo Squid, exercendo a função de servidor para o cliente, e a função de cliente para o servidor destino.

Sobre as regras http_access adicionais, é necessário entender que antes de receber requisições HTTP criptografadas com TLS/SSL, o Squid recebe do cliente uma requisição CONNECT. Essa requisição é uma abstração do TLS handshake, etapa em que o cliente verifica a confiança no servidor com base em sua assinatura.

O conjunto de todas as requisições da imagem, com exceção de “data exchange (HTTP or other)” são vistas pelo Squid como uma única requisição CONNECT.

Depois de receber uma requisição CONNECT, caso ela tenha sido liberada, o Squid recebe em seguida uma requisição HTTPS. Como configuramos ssl_bump bump all, o Squid decriptografará esta última requisição, fazendo com que as regras http_access se apliquem como se fosse uma requisição HTTP.

Nas regras definidas na configuração, CONNECT é um valor pré-definido pelo Squid.

  • A primeira regra bloqueia requisições que não sejam destinadas a uma porta 80 ou 443.
  • A segunda regra bloqueia requisições CONNECT que não forem destinadas a uma porta 443.
  • A terceira regra bloqueia requisições recebidas através da porta 3128 (proxy direto).
  • A quarta regra libera requisições CONNECT destinadas a uma porta 443.
  • A quinta regra libera requisições para as URLs http://example.com, http://example.com/, https://example.com e https://example.com/.
  • Por fim, a sexta regra bloqueia qualquer requisição que não foi bloqueada ou liberada anteriormente.

Melhorias no filtro

Para termos ainda mais controle em nosso filtro de conteúdo web, podemos utilizar a diretiva external_acl_type. A ideia é passar ao Squid um programa customizado, que lerá algumas características de cada requisição, como URL, método e headers, e retornará sua liberação ou bloqueio. A documentação da diretiva logformat pode ser útil para visualizar quais são as possibilidades.

Referências

[1] “Big Breaches: What we learned from some of the world’s most disruptive cyberattacks.”, https://online.stanford.edu/big-breaches-what-we-learned-some-worlds-most-disruptive-cyberattacks. Accessed 21 Aug. 2023.

[2] “Squid 5.9 Configuration File.”, www.squid-cache.org/Versions/v5/cfgman/. Accessed 21 Aug. 2023.

[3] “Squid Web Proxy Wiki.”, wiki.squid-cache.org/. Accessed 21 Aug. 2023.

--

--