Skip to content

Certificate Pinning

A fixação de certificados pode ser empregada em aplicativos Android para proteger contra ataques do tipo Machine-in-the-Middle (MITM), garantindo que o aplicativo se comunique exclusivamente com endpoints remotos que possuem identidades específicas.

Embora eficaz quando implementada corretamente, implementações inseguras podem potencialmente permitir que invasores leiam e modifiquem toda a comunicação. Para detalhes mais gerais sobre fixação, consulte Pinning de Identidade Inseguro.

Existem várias abordagens para fixação de certificados, dependendo do nível de API do aplicativo e das bibliotecas utilizadas. Abaixo, destacamos os métodos mais comuns. Para um mergulho mais profundo nas implementações específicas, consulte "Deep Dive into Certificate Pinning on Android".

Considerações importantes:

A fixação de certificados é uma prática de reforço de segurança, mas não é infalível. Existem várias maneiras pelas quais um invasor pode contorná-la, como:

  • Modificar a lógica de validação de certificados no TrustManager do aplicativo.
  • Substituir certificados fixados armazenados em diretórios de recursos (res/raw/, assets/).
  • Alterar ou remover pins na Configuração de Segurança de Rede.

Qualquer modificação desse tipo invalida a assinatura do APK, exigindo que o invasor reempacote e reassine o APK. Para mitigar esses riscos, proteções adicionais, como verificações de integridade, verificação em tempo de execução e ofuscação, podem ser necessárias. Para mais informações sobre técnicas específicas, consulte Contornando o Certificate Pinning.

Pinning via Network Security Configuration (API 24+)

A Network Security Configuration (NSC) é a forma preferida e recomendada para implementar a fixação de certificados no Android, pois oferece uma abordagem declarativa, sustentável e segura sem exigir alterações de código. Ela se aplica a todo o tráfego de rede gerenciado pelo framework Android dentro do aplicativo, incluindo conexões baseadas em HttpsURLConnection e requests de WebView (a menos que um TrustManager personalizado seja usado). Para comunicação a partir de código nativo, a NSC não se aplica, e outros mecanismos precisam ser considerados.

Ao tentar estabelecer uma conexão com um endpoint remoto, o sistema irá:

  • Obter e validar o certificado recebido.
  • Extrair a chave pública.
  • Calcular um resumo (digest) sobre a chave pública extraída.
  • Comparar o resumo com o conjunto de pins locais.

Se pelo menos um dos resumos fixados corresponder, a cadeia de certificados será considerada válida e a conexão prosseguirá.

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <!-- Use a fixação de certificado para acesso ao site da OWASP incluindo subdomínios -->
        <domain includeSubdomains="true">owasp.org</domain>
        <pin-set expiration="2028-12-31">
            <!-- Hash da chave pública (SubjectPublicKeyInfo do certificado X.509) da
            CA intermediária do certificado do servidor do site da OWASP -->
            <pin digest="SHA-256">YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=</pin>
            <!-- Hash da chave pública (SubjectPublicKeyInfo do certificado X.509) da
            CA raiz do certificado do servidor do site da OWASP -->
            <pin digest="SHA-256">Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys=</pin>
        </pin-set>
    </domain-config>
</network-security-config>

Considerações importantes:

  • Pins de backup: Sempre inclua um pin de backup para manter a conectividade se o certificado principal for alterado inesperadamente.
  • Datas de expiração: Defina uma data de expiração apropriada e garanta atualizações oportunas para evitar que o aplicativo ignore a fixação após a data ter passado.
  • Escopo de aplicação: Esteja ciente de que esta configuração se aplica apenas a conexões feitas usando HttpsURLConnection ou bibliotecas que dependem dele. Outras bibliotecas ou frameworks de rede podem exigir implementações de fixação separadas.

Pinning usando TrustManagers personalizados

Antes da Network Security Configuration estar disponível, a maneira recomendada de implementar a fixação de certificados era criar um TrustManager personalizado (usando as APIs javax.net.ssl) e substituir a validação padrão de certificados. Você ainda pode usar essa abordagem em versões modernas do Android para flexibilidade ou quando precisar de controle mais direto.

Esta abordagem envolve:

  1. Carregar o(s) certificado(s) do servidor em um KeyStore.
  2. Criar um TrustManager personalizado que confie apenas no(s) certificado(s) no KeyStore.
  3. Inicializar um SSLContext com o TrustManager personalizado.
  4. Aplicar o SSLContext personalizado como a fábrica de soquetes para as conexões de rede (por exemplo, HttpsURLConnection).

Nota importante: Esta é uma abordagem de baixo nível e propensa a erros se não for feita com cuidado. Algumas considerações importantes incluem:

Pinning usando bibliotecas de terceiros

Várias bibliotecas de terceiros oferecem suporte integrado para fixação de certificados, simplificando o processo de implementação em alguns casos. Essas bibliotecas normalmente utilizam o método de TrustManager personalizado, fornecendo abstrações de nível superior e recursos adicionais. Exemplos notáveis incluem:

  • OkHttp: oferece pinning em seu CertificatePinner. Nos bastidores, ele usa um TrustManager personalizado para impor regras de fixação.

Pinning em WebViews

Para tráfego de WebView no aplicativo no Android, a abordagem mais fácil é confiar na Network Security Configuration. Como o Android aplica automaticamente as regras de NSC ao tráfego do WebView dentro do mesmo aplicativo, quaisquer regras de fixação que você configurar em network_security_config.xml também se aplicarão a recursos carregados naquele WebView.

Se você precisar de personalização adicional além do que a NSC oferece, poderia implementar a fixação interceptando requests no nível do WebView (por exemplo, usando shouldInterceptRequest e um TrustManager personalizado)))), mas na maioria dos casos o suporte integrado é suficiente e mais simples.

Pinning em código nativo

Também é possível implementar a fixação em código nativo (C/C++/Rust). Ao incorporar ou verificar dinamicamente certificados dentro de bibliotecas nativas compiladas (arquivos .so), você pode aumentar a dificuldade de contornar ou modificar as verificações de fixação via engenharia reversa típica de APK.

Dito isso, esta abordagem requer experiência significativa em segurança e um design cuidadoso para gerenciar certificados ou hashes de chave pública no espaço nativo. A manutenção e a depuração também normalmente se tornam mais complexas.

Pinning em frameworks multiplataforma

Frameworks multiplataforma como Flutter, React Native, Cordova e Xamarin frequentemente exigem considerações especiais para fixação de certificados, pois podem não usar a mesma pilha de rede que aplicativos nativos. Por exemplo, o Flutter depende de seu próprio HttpClient Dart (com BoringSSL) em vez da pilha de rede da plataforma, enquanto o Cordova faz requests de rede através de JavaScript em um WebView. Como resultado, o comportamento de fixação varia—alguns frameworks fornecem opções de configuração integradas, outros dependem de plugins de terceiros, e alguns não oferecem suporte direto, mas permitem implementação manual via APIs. Entender como um framework lida com rede é crucial para garantir a aplicação adequada da fixação.