Certificate pinning: quando e como usar com cautela

1. O que é Certificate Pinning e por que existe?

Certificate pinning é a prática de fixar (“prender”) a identidade criptográfica de um servidor — seja seu certificado digital ou sua chave pública — diretamente no cliente que realiza a conexão TLS. Em vez de confiar cegamente em toda a cadeia de Autoridades Certificadoras (CAs), o cliente valida que o certificado apresentado corresponde exatamente ao que foi previamente configurado.

O objetivo principal é mitigar ataques Man-in-the-Middle (MITM), mesmo quando uma CA é comprometida ou quando um atacante consegue emitir um certificado válido para o domínio alvo. Em vez de confiar na hierarquia de CAs, o cliente confia em um certificado ou chave específica.

Existem duas abordagens principais:

  • Pinning de certificado: fixa o certificado folha completo (o certificado do servidor). É frágil — qualquer renovação que mude o certificado quebra o pin.
  • Pinning de chave pública (SPKI - Subject Public Key Info): fixa apenas a chave pública contida no certificado. Isso permite renovar o certificado (com nova validade, novos SANs etc.) desde que a mesma chave pública seja reutilizada.

A diferença é crucial: com SPKI, você pode renovar o certificado sem quebrar o pin. Com pinning de certificado, qualquer renovação exige atualização do cliente.

2. Cenários onde o pinning é recomendado (e onde não é)

Recomendado

  • Aplicações mobile nativas que se comunicam com APIs críticas (bancos, saúde, pagamentos). O app pode ser atualizado via loja, e o controle sobre a infraestrutura é total.
  • APIs internas ou fechadas onde você controla tanto o servidor quanto o cliente (ex: microsserviços em uma VPN corporativa).
  • Sistemas de alta segurança (fintech, governo, IoT crítico) onde o risco de uma CA comprometida supera o custo operacional do pinning.

Não recomendado

  • Sites públicos comuns (blogs, e-commerce não crítico). O custo de manutenção supera o benefício — se o certificado expirar ou for renovado, todos os usuários ficam bloqueados até atualizarem o navegador ou o app.
  • Aplicações com rotação frequente de certificados (ex: Let's Encrypt a cada 90 dias). Manter pins atualizados em múltiplos clientes é inviável.
  • Cenários com redes corporativas ou proxies (antivírus, firewalls que inspecionam TLS). O pinning quebra essas inspeções legítimas, gerando suporte e insatisfação.

3. Modalidades de pinning: certificado vs. chave pública

Característica Pinning de certificado Pinning de chave pública (SPKI)
O que é fixado Certificado folha completo Apenas a chave pública
Tolerância a renovação Baixa (exige novo certificado idêntico) Alta (mesma chave, novo certificado)
Risco de lockout Alto (qualquer renovação quebra) Moderado (só quebra se a chave mudar)
Complexidade Baixa (hash do certificado) Média (extrair SPKI do certificado)

Backup pins: a prática recomendada é manter pelo menos dois pins — um primário (atual) e um ou mais de backup (para certificados futuros ou de contingência). Isso evita lockout total se o certificado primário precisar ser trocado antes do previsto.

Exemplo de estratégia: pin da chave pública atual + pin da chave pública do próximo certificado (já provisionado mas ainda não ativo). Se o certificado atual expirar inesperadamente, o backup pin permite a transição.

4. Implementação prática: exemplos de código

Android (Network Security Config)

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">api.exemplo.com</domain>
        <pin-set expiration="2025-12-31">
            <pin digest="SHA-256">base64hash_do_certificado_primario=</pin>
            <pin digest="SHA-256">base64hash_do_certificado_backup=</pin>
        </pin-set>
        <!-- Fallback para CA normal se o pin falhar -->
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </domain-config>
</network-security-config>

O atributo expiration no pin-set é essencial: define até quando o pin é válido. Após essa data, o Android ignora o pin e usa a validação normal da CA. Isso permite migração suave sem exigir atualização do app.

iOS (TrustKit)

// Configuração TrustKit (exemplo em Swift)
let trustKitConfig = [
    kTSKSwizzleNetworkDelegates: false,
    kTSKPinnedDomains: [
        "api.exemplo.com": [
            kTSKEnforcePinning: true,
            kTSKExpirationDate: "2025-12-31",
            kTSKPublicKeyHashes: [
                "base64hash_da_chave_publica_primaria=",
                "base64hash_da_chave_publica_backup="
            ]
        ]
    ]
]
TrustKit.initSharedInstance(withConfiguration: trustKitConfig)

Node.js (axios com custom agent)

const https = require('https');
const axios = require('axios');
const crypto = require('crypto');
const fs = require('fs');

// Hash esperado da chave pública (SPKI)
const EXPECTED_PIN = 'base64hash_da_chave_publica=';

const agent = new https.Agent({
  checkServerIdentity: (host, cert) => {
    // Extrair SPKI do certificado
    const spki = cert.pubkey;
    const hash = crypto.createHash('sha256').update(spki).digest('base64');

    if (hash !== EXPECTED_PIN) {
      return new Error(`Pin mismatch: esperado ${EXPECTED_PIN}, recebido ${hash}`);
    }
    return undefined; // sucesso
  }
});

axios.get('https://api.exemplo.com/dados', { httpsAgent: agent })
  .then(res => console.log(res.data))
  .catch(err => console.error('Erro de pinning:', err.message));

O HPKP (HTTP Public Key Pinning) foi deprecado em todos os navegadores modernos devido a abusos e lockouts catastróficos (ex: sites inteiros ficaram inacessíveis por meses). Hoje, navegadores não suportam mais pinning via header HTTP. A alternativa moderna é o Certificate Transparency (CT), que verifica logs públicos em vez de fixar chaves.

5. Armadilhas e riscos do pinning mal feito

  • Lockout acidental: o cenário mais temido. Se o certificado expirar e não houver backup pin, todos os clientes com pinning ativo perdem acesso ao serviço. Sem atualização do app, o serviço fica inacessível.
  • Falta de fallback: não permitir bypass em redes corporativas (proxy, antivírus que inspecionam TLS) gera suporte e reclamações. O pinning deve ser um reforço, não a única âncora de confiança.
  • Complexidade de deploy: atualizar pins exige nova versão do app (app store review). Se o certificado precisar ser trocado com urgência (comprometimento), o tempo de resposta é de dias, não minutos.
  • Ataque de downgrade: se o pinning não for aplicado em todas as camadas (ex: HTTP/2 vs HTTP/1.1), um atacante pode forçar o downgrade para HTTP/1.1 sem pinning e contornar a proteção.

6. Boas práticas e estratégias de mitigação

  1. Sempre usar pinning de chave pública (SPKI) em vez de certificado folha. A flexibilidade para renovar certificados com a mesma chave é essencial.
  2. Implementar expiration no pin (data de validade). Após essa data, o cliente deve ignorar o pin e usar validação normal da CA. Isso permite transição suave sem exigir atualização do app.
  3. Usar fallback trust chain (CA normal) + pinning como reforço. Configure o cliente para: primeiro tentar pinning; se falhar, tentar validação normal da CA; se ambos falharem, rejeitar a conexão.
  4. Monitorar ativamente certificados com ferramentas como certificate-transparency (logs públicos) e crt.sh. Isso permite detectar emissões não autorizadas antes que causem dano.
  5. Testar em staging com pinning report-only antes de aplicar em produção. No Android, use pin-set com expiration no passado para testar o comportamento sem bloquear tráfego real.

7. Alternativas modernas ao pinning tradicional

  • Certificate Transparency (CT): logs públicos de emissão de certificados. Clientes podem verificar se o certificado foi registrado em logs auditáveis. Detecta CAs maliciosas sem fixar chaves.
  • Expect-CT header: forçava o navegador a verificar CT. Foi deprecado em favor de CT embutido nos navegadores.
  • TLS 1.3 + 0-RTT: reduz a janela de ataque MITM ao minimizar o handshake e utilizar criptografia mais robusta.
  • Certificados de curta duração (short-lived certificates): com Let's Encrypt (90 dias) ou certificados de 24h, a janela de exposição é mínima. Pinning se torna desnecessário — mesmo que um certificado seja comprometido, ele expira rapidamente.

8. Conclusão: usar com cautela, não como dogma

Certificate pinning é uma ferramenta de defesa em profundidade, não uma bala de prata. Em sites públicos, o custo operacional supera o benefício — prefira Certificate Transparency + monitoramento. Em aplicações mobile críticas com ciclo de atualização controlado, o pinning (especialmente SPKI com backup pins e expiration) agrega segurança real.

Checklist para decidir:
- Vale o custo operacional de manter pins atualizados?
- Tenho controle total sobre a renovação de certificados?
- Posso atualizar o cliente rapidamente se algo der errado?
- Existe fallback para redes corporativas (proxy, antivírus)?

Se a resposta for "sim" para todas, o pinning pode ser uma camada extra de segurança. Caso contrário, as alternativas modernas (CT, certificados curtos, TLS 1.3) oferecem proteção similar com muito menos risco operacional.

Lembre-se: segurança não é sobre bloquear tudo, mas sobre equilibrar proteção com usabilidade e resiliência.

Referências