Voltar ao blog

Solução de Problemas com SSL/TLS ao Usar Proxy: Guia Completo

Analisamos erros típicos de SSL/TLS ao trabalhar através de proxy: desde problemas com certificados até configuração de túneis HTTPS. Soluções práticas com exemplos de código.

📅16 de dezembro de 2025
```html

Solução de problemas com SSL/TLS ao usar proxy: guia completo

Erros SSL/TLS são um dos problemas mais frequentes ao trabalhar através de servidores proxy. A configuração incorreta leva a falhas de conexão, vazamento de dados e impossibilidade de fazer parsing de recursos protegidos. Neste guia, analisaremos as causas dos erros e formas de resolvê-los com exemplos específicos de código.

Como funciona SSL/TLS através de proxy

Antes de resolver problemas, é importante entender o mecanismo de funcionamento de conexões protegidas através de proxy. Existem duas abordagens fundamentalmente diferentes para fazer proxy de tráfego HTTPS, e cada uma tem suas próprias características, vantagens e possíveis pontos de falha.

Tunelamento transparente (CONNECT)

Ao usar o método CONNECT, o servidor proxy cria um túnel TCP entre o cliente e o servidor de destino. O proxy não vê o conteúdo do tráfego — ele simplesmente transmite bytes criptografados em ambas as direções. Este é o método mais seguro e comum para trabalhar com HTTPS através de proxy.

O processo de estabelecimento de conexão funciona da seguinte forma: o cliente envia uma solicitação CONNECT para o proxy especificando o host e porta de destino. O proxy estabelece uma conexão TCP com o servidor de destino e retorna ao cliente uma resposta 200 Connection Established. Depois disso, o cliente realiza o handshake TLS diretamente com o servidor de destino através do túnel estabelecido.

# Esquema de túnel CONNECT
Cliente → Proxy: CONNECT example.com:443 HTTP/1.1
Proxy → Servidor: [Conexão TCP na porta 443]
Proxy → Cliente: HTTP/1.1 200 Connection Established
Cliente ↔ Servidor: [Handshake TLS através do túnel]
Cliente ↔ Servidor: [Tráfego criptografado]

Proxy MITM (interceptação)

Alguns proxies (especialmente corporativos) usam a técnica Man-in-the-Middle: eles terminam a conexão TLS do seu lado, descriptografam o tráfego e depois estabelecem uma nova conexão TLS com o servidor de destino. Para isso, o proxy gera seu próprio certificado para cada domínio, assinado pelo certificado raiz do proxy.

Esta abordagem permite inspecionar e filtrar tráfego HTTPS, mas requer a instalação do certificado raiz do proxy no armazenamento de certificados confiáveis do cliente. É aqui que surgem a maioria dos problemas com SSL/TLS ao trabalhar através de redes corporativas.

Erros típicos e suas causas

Vamos considerar os erros SSL/TLS mais comuns ao trabalhar através de proxy. Compreender a causa de cada erro é a chave para resolver o problema rapidamente.

SSL: CERTIFICATE_VERIFY_FAILED

Este erro significa que o cliente não consegue verificar a autenticidade do certificado do servidor. Pode haver várias causas: o proxy usa inspeção MITM com certificado raiz não instalado, o certificado do servidor de destino expirou ou é auto-assinado, ou falta um certificado intermediário na cadeia.

# Python - mensagem de erro típica
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] 
certificate verify failed: unable to get local issuer certificate

# Node.js
Error: unable to verify the first certificate

# cURL
curl: (60) SSL certificate problem: unable to get local issuer certificate

SSL: WRONG_VERSION_NUMBER

O erro ocorre quando o cliente tenta estabelecer uma conexão TLS, mas recebe uma resposta em formato inesperado. Na maioria das vezes, isso acontece quando o proxy não suporta o método CONNECT e tenta processar a solicitação HTTPS como HTTP comum. Também pode ser causado por porta ou protocolo incorretos.

TLSV1_ALERT_PROTOCOL_VERSION

O servidor rejeita a conexão devido a uma versão incompatível do protocolo TLS. Os servidores modernos desabilitam versões antigas do TLS 1.0 e TLS 1.1 por razões de segurança. Se o proxy ou cliente estiverem configurados para usar versões antigas, a conexão será rejeitada.

SSLV3_ALERT_HANDSHAKE_FAILURE

O cliente e servidor não conseguiram negociar os parâmetros de criptografia. Isso pode ocorrer devido à falta de cipher suites comuns, problemas com SNI (Server Name Indication) ou incompatibilidade de bibliotecas criptográficas.

Erro Causa provável Solução
CERTIFICATE_VERIFY_FAILED Proxy MITM, certificado expirado Instalar certificado raiz do proxy
WRONG_VERSION_NUMBER HTTP em vez de HTTPS, sem suporte CONNECT Verificar configurações de proxy e protocolo
PROTOCOL_VERSION Versão TLS desatualizada Atualizar versão mínima de TLS
HANDSHAKE_FAILURE Cipher suites incompatíveis Configurar lista de cifras

Problemas com certificados

Certificados são a fonte mais frequente de problemas ao trabalhar através de proxy. Vamos considerar os principais cenários e formas de resolvê-los.

Instalação do certificado raiz do proxy

Se o proxy usar inspeção MITM, é necessário adicionar seu certificado raiz ao armazenamento de certificados confiáveis. O processo depende do sistema operacional e da linguagem de programação usada.

# Linux: adicionar certificado ao armazenamento do sistema
sudo cp proxy-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates

# macOS: adicionar ao Keychain
sudo security add-trusted-cert -d -r trustRoot \
    -k /Library/Keychains/System.keychain proxy-ca.crt

# Windows PowerShell (como administrador)
Import-Certificate -FilePath "proxy-ca.crt" `
    -CertStoreLocation Cert:\LocalMachine\Root

Especificação do certificado no código

Às vezes é mais conveniente especificar o caminho para o certificado diretamente no código, especialmente ao trabalhar em contêineres ou em servidores sem acesso root. Isso permite evitar modificações nas configurações do sistema.

# Python: especificar CA-bundle personalizado
import requests

# Forma 1: especificar caminho para arquivo de certificado
response = requests.get(
    'https://example.com',
    proxies={'https': 'http://proxy:8080'},
    verify='/path/to/proxy-ca.crt'
)

# Forma 2: combinar com certificados do sistema
import certifi
import ssl

# Criar arquivo de certificados combinado
with open('combined-ca.crt', 'w') as combined:
    with open(certifi.where()) as system_certs:
        combined.write(system_certs.read())
    with open('proxy-ca.crt') as proxy_cert:
        combined.write(proxy_cert.read())

response = requests.get(url, verify='combined-ca.crt')

Desabilitação da verificação de certificados

Em alguns casos (apenas para testes e depuração!) pode ser necessário desabilitar a verificação de certificados. Isso não é seguro e não deve ser usado em produção, pois torna a conexão vulnerável a ataques MITM.

⚠️ Aviso: Desabilitar a verificação de certificados torna a conexão vulnerável a interceptação. Use apenas para depuração em ambiente isolado, nunca em produção!

# Python - APENAS para depuração!
import requests
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

response = requests.get(
    'https://example.com',
    proxies={'https': 'http://proxy:8080'},
    verify=False  # Não seguro!
)

Configuração de túneis CONNECT

A configuração correta do túnel CONNECT é a chave para o funcionamento estável de HTTPS através de proxy. Vamos considerar as características de configuração para diferentes cenários de uso.

Verificação de suporte CONNECT

Nem todos os proxies suportam o método CONNECT. Proxies HTTP podem ser configurados apenas para fazer proxy de tráfego HTTP. Antes de usar, certifique-se de que o proxy suporta tunelamento HTTPS.

# Verificar suporte CONNECT via netcat/telnet
echo -e "CONNECT example.com:443 HTTP/1.1\r\nHost: example.com:443\r\n\r\n" | \
    nc proxy.example.com 8080

# Resposta esperada em caso de sucesso:
# HTTP/1.1 200 Connection Established

# Possíveis respostas em caso de erro:
# HTTP/1.1 403 Forbidden - CONNECT proibido
# HTTP/1.1 405 Method Not Allowed - método não suportado

Autenticação em solicitações CONNECT

Ao usar um proxy com autenticação, é importante transmitir corretamente as credenciais. O cabeçalho Proxy-Authorization deve estar presente na solicitação CONNECT.

# Python: autenticação via URL
import requests

proxy_url = 'http://username:password@proxy.example.com:8080'
response = requests.get(
    'https://target.com',
    proxies={'https': proxy_url}
)

# Python: autenticação via cabeçalhos (para casos complexos)
import base64

credentials = base64.b64encode(b'username:password').decode('ascii')
session = requests.Session()
session.headers['Proxy-Authorization'] = f'Basic {credentials}'
session.proxies = {'https': 'http://proxy.example.com:8080'}

response = session.get('https://target.com')

Trabalho com proxy SOCKS5

Proxies SOCKS5 funcionam em um nível mais baixo e não requerem tratamento especial de HTTPS. Eles simplesmente tunelizam conexões TCP, o que os torna ideais para trabalhar com qualquer protocolo.

# Python com PySocks
import requests

proxies = {
    'http': 'socks5h://user:pass@proxy:1080',
    'https': 'socks5h://user:pass@proxy:1080'
}

# socks5h - resolução DNS através do proxy
# socks5 - resolução DNS local

response = requests.get('https://example.com', proxies=proxies)

Soluções para diferentes linguagens de programação

Cada linguagem e biblioteca têm suas próprias características ao trabalhar com SSL/TLS através de proxy. Vamos considerar as opções mais comuns com exemplos completos de código.

Python (requests + urllib3)

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.ssl_ import create_urllib3_context
import ssl

class TLSAdapter(HTTPAdapter):
    """Adaptador com parâmetros TLS configuráveis"""
    
    def __init__(self, ssl_context=None, **kwargs):
        self.ssl_context = ssl_context
        super().__init__(**kwargs)
    
    def init_poolmanager(self, *args, **kwargs):
        if self.ssl_context:
            kwargs['ssl_context'] = self.ssl_context
        return super().init_poolmanager(*args, **kwargs)

# Criar contexto com configurações modernas
ctx = create_urllib3_context()
ctx.minimum_version = ssl.TLSVersion.TLSv1_2
ctx.set_ciphers('ECDHE+AESGCM:DHE+AESGCM:ECDHE+CHACHA20')

# Carregar certificado adicional
ctx.load_verify_locations('proxy-ca.crt')

session = requests.Session()
session.mount('https://', TLSAdapter(ssl_context=ctx))
session.proxies = {
    'http': 'http://proxy:8080',
    'https': 'http://proxy:8080'
}

response = session.get('https://example.com')
print(response.status_code)

Node.js (axios + https-proxy-agent)

const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');
const fs = require('fs');
const https = require('https');

// Carregar certificado CA adicional
const customCA = fs.readFileSync('proxy-ca.crt');

const agent = new HttpsProxyAgent({
    host: 'proxy.example.com',
    port: 8080,
    auth: 'username:password',
    ca: customCA,
    rejectUnauthorized: true  // Não desabilite em produção!
});

const client = axios.create({
    httpsAgent: agent,
    proxy: false  // Importante: desabilitar proxy integrado do axios
});

async function fetchData() {
    try {
        const response = await client.get('https://example.com');
        console.log(response.data);
    } catch (error) {
        if (error.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {
            console.error('Problema com certificado:', error.message);
        }
        throw error;
    }
}

fetchData();

Go (net/http)

package main

import (
    "crypto/tls"
    "crypto/x509"
    "io/ioutil"
    "net/http"
    "net/url"
    "log"
)

func main() {
    // Carregar certificado adicional
    caCert, err := ioutil.ReadFile("proxy-ca.crt")
    if err != nil {
        log.Fatal(err)
    }
    
    caCertPool := x509.NewCertPool()
    caCertPool.AppendCertsFromPEM(caCert)
    
    // Configurar TLS
    tlsConfig := &tls.Config{
        RootCAs:    caCertPool,
        MinVersion: tls.VersionTLS12,
    }
    
    // Configurar proxy
    proxyURL, _ := url.Parse("http://user:pass@proxy:8080")
    
    transport := &http.Transport{
        Proxy:           http.ProxyURL(proxyURL),
        TLSClientConfig: tlsConfig,
    }
    
    client := &http.Client{Transport: transport}
    
    resp, err := client.Get("https://example.com")
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()
    
    log.Printf("Status: %s", resp.Status)
}

cURL (linha de comando)

# Solicitação básica através de proxy
curl -x http://proxy:8080 https://example.com

# Com autenticação
curl -x http://proxy:8080 -U username:password https://example.com

# Com especificação de certificado CA
curl -x http://proxy:8080 --cacert proxy-ca.crt https://example.com

# Forçar uso de TLS 1.2+
curl -x http://proxy:8080 --tlsv1.2 https://example.com

# Depuração de handshake TLS
curl -x http://proxy:8080 -v --trace-ascii - https://example.com 2>&1 | \
    grep -E "(SSL|TLS|certificate)"

Detecção e bypass de inspeção MITM

Algumas redes (corporativas, Wi-Fi público) usam inspeção MITM transparente de tráfego HTTPS. Isso pode causar problemas com certificate pinning e prejudicar o funcionamento de aplicações que esperam certificados específicos.

Detecção de proxy MITM

import ssl
import socket

def check_certificate_issuer(hostname, port=443):
    """Verifica quem emitiu o certificado do site"""
    context = ssl.create_default_context()
    
    with socket.create_connection((hostname, port)) as sock:
        with context.wrap_socket(sock, server_hostname=hostname) as ssock:
            cert = ssock.getpeercert()
            
            issuer = dict(x[0] for x in cert['issuer'])
            subject = dict(x[0] for x in cert['subject'])
            
            print(f"Subject: {subject.get('commonName')}")
            print(f"Issuer: {issuer.get('commonName')}")
            print(f"Organization: {issuer.get('organizationName')}")
            
            # Proxies MITM corporativos conhecidos
            mitm_indicators = [
                'Zscaler', 'BlueCoat', 'Symantec', 'Fortinet',
                'Palo Alto', 'McAfee', 'Cisco', 'Corporate'
            ]
            
            issuer_str = str(issuer)
            for indicator in mitm_indicators:
                if indicator.lower() in issuer_str.lower():
                    print(f"⚠️ Proxy MITM detectado: {indicator}")
                    return True
            
            return False

# Verificação
check_certificate_issuer('google.com')

Trabalho em condições de MITM

Se um proxy MITM for detectado, existem várias estratégias de trabalho. Você pode instalar o certificado raiz do proxy (se for uma rede corporativa confiável), usar portas ou protocolos alternativos, ou aplicar VPN para contornar a inspeção.

# Obter certificado do proxy MITM para instalação
openssl s_client -connect example.com:443 -proxy proxy:8080 \
    -showcerts 2>/dev/null | \
    openssl x509 -outform PEM > mitm-cert.pem

# Visualizar informações do certificado
openssl x509 -in mitm-cert.pem -text -noout | head -20

Ferramentas de diagnóstico

O diagnóstico correto é metade da solução do problema. Vamos considerar ferramentas e métodos para depuração de conexões SSL/TLS através de proxy.

OpenSSL para diagnóstico

# Verificar conexão através de proxy
openssl s_client -connect example.com:443 \
    -proxy proxy.example.com:8080 \
    -servername example.com

# Verificar cadeia de certificados
openssl s_client -connect example.com:443 \
    -proxy proxy:8080 \
    -showcerts 2>/dev/null | \
    grep -E "(Certificate chain|s:|i:)"

# Testar versão específica de TLS
openssl s_client -connect example.com:443 \
    -proxy proxy:8080 \
    -tls1_2

# Verificar cipher suites suportadas
openssl s_client -connect example.com:443 \
    -proxy proxy:8080 \
    -cipher 'ECDHE-RSA-AES256-GCM-SHA384'

Script Python para diagnóstico

import ssl
import socket
import requests
from urllib.parse import urlparse

def diagnose_ssl_proxy(target_url, proxy_url):
    """Diagnóstico abrangente de SSL através de proxy"""
    
    print(f"🔍 Diagnóstico: {target_url}")
    print(f"📡 Proxy: {proxy_url}\n")
    
    # 1. Verificar disponibilidade do proxy
    proxy = urlparse(proxy_url)
    try:
        sock = socket.create_connection(
            (proxy.hostname, proxy.port), 
            timeout=10
        )
        sock.close()
        print("✅ Proxy disponível")
    except Exception as e:
        print(f"❌ Proxy indisponível: {e}")
        return
    
    # 2. Verificar método CONNECT
    try:
        response = requests.get(
            target_url,
            proxies={'https': proxy_url},
            timeout=15
        )
        print(f"✅ Conexão HTTPS bem-sucedida: {response.status_code}")
    except requests.exceptions.SSLError as e:
        print(f"❌ Erro SSL (tentativa): {e}")
        
        # Tentar com verificação desabilitada para diagnóstico
        try:
            response = requests.get(
                target_url,
                proxies={'https': proxy_url},
                verify=False,
                timeout=15
            )
            print("⚠️ Conexão funciona sem verificação de certificado")
            print("   Provável problema com certificado CA do proxy")
        except Exception as e2:
            print(f"❌ Não funciona nem sem verificação: {e2}")
    
    except Exception as e:
        print(f"❌ Erro de conexão: {e}")
    
    # 3. Informações sobre SSL
    print(f"\n📋 Versão OpenSSL: {ssl.OPENSSL_VERSION}")
    print(f"📋 Caminhos de verificação padrão: {ssl.get_default_verify_paths()}")

# Uso
diagnose_ssl_proxy(
    'https://httpbin.org/ip',
    'http://proxy:8080'
)

Wireshark para análise profunda

Para casos complexos, use Wireshark com filtro de tráfego TLS. Isso permite ver os detalhes do handshake e determinar exatamente o momento da falha.

# Filtros Wireshark para análise TLS
tls.handshake.type == 1          # Client Hello
tls.handshake.type == 2          # Server Hello
tls.handshake.type == 11         # Certificate
tls.alert_message                 # Alertas TLS (erros)

# Capturar tráfego com tcpdump
tcpdump -i eth0 -w ssl_debug.pcap \
    'port 443 or port 8080' -c 1000

Melhores práticas de trabalho seguro

Seguir as melhores práticas ajudará a evitar a maioria dos problemas com SSL/TLS e garantirá a segurança dos seus dados ao trabalhar através de proxy.

Configuração de TLS

  • Use no mínimo TLS 1.2, preferencialmente TLS 1.3
  • Configure cipher suites modernos (ECDHE, AES-GCM, ChaCha20)
  • Ative verificação de certificados (nunca desabilite verify em produção)
  • Atualize regularmente o CA-bundle e bibliotecas criptográficas

Trabalho com proxy

  • Prefira proxies com suporte completo ao método CONNECT para tráfego HTTPS
  • Use SOCKS5 para tunelamento universal
  • Ao trabalhar com proxies residenciais, considere possíveis características de redes de provedores
  • Armazene credenciais de proxy em variáveis de ambiente, não no código

Tratamento de erros

import requests
from requests.exceptions import SSLError, ProxyError, ConnectionError
import time

def robust_request(url, proxy, max_retries=3):
    """Solicitação resistente a erros através de proxy"""
    
    for attempt in range(max_retries):
        try:
            response = requests.get(
                url,
                proxies={'https': proxy},
                timeout=30
            )
            return response
            
        except SSLError as e:
            print(f"Erro SSL (tentativa {attempt + 1}): {e}")
            # Erros SSL geralmente não são corrigidos por retry
            if 'CERTIFICATE_VERIFY_FAILED' in str(e):
                raise  # Requer correção de configuração
                
        except ProxyError as e:
            print(f"Erro de proxy (tentativa {attempt + 1}): {e}")
            time.sleep(2 ** attempt)  # Atraso exponencial
            
        except ConnectionError as e:
            print(f"Erro de conexão (tentativa {attempt + 1}): {e}")
            time.sleep(2 ** attempt)
    
    raise Exception(f"Falha ao executar solicitação após {max_retries} tentativas")

Checklist de resolução de problemas

Ao encontrar erros SSL/TLS, siga esta ordem de diagnóstico:

  1. Verifique a disponibilidade do servidor proxy (ping, telnet)
  2. Certifique-se de que o método CONNECT é suportado
  3. Verifique a correção das credenciais de autenticação
  4. Estude o certificado usando openssl s_client
  5. Verifique a presença de inspeção MITM
  6. Instale os certificados CA necessários
  7. Atualize a versão de TLS e cipher suites

💡 Dica: A maioria dos problemas de SSL/TLS ao trabalhar através de proxy está relacionada a certificados. Comece o diagnóstico verificando a cadeia de certificados e certifique-se de que todos os certificados intermediários estão presentes.

Conclusão

Problemas de SSL/TLS ao trabalhar através de proxy são solucionáveis com uma abordagem sistemática para diagnóstico. Os pontos-chave são: compreender a diferença entre tunelamento CONNECT e proxy MITM, configuração correta de certificados e uso de versões modernas do protocolo TLS. A maioria dos erros está relacionada à falta de certificados CA necessários ou incompatibilidade de parâmetros criptográficos.

Para tarefas de parsing e automação que requerem funcionamento estável de HTTPS, recomenda-se usar proxies de qualidade com suporte completo ao método CONNECT — mais detalhes sobre opções em proxycove.com.

```