Skip to content

MASTG-TEST-0022: Testando Armazenamentos de Certificados Personalizados e Certificate Pinning

Deprecated Test

This test is deprecated and should not be used anymore. Reason: New version available in MASTG V2

Please check the following MASTG v2 tests that cover this v1 test:

Visão Geral

Análise Estática

Configuração de Segurança de Rede

Inspecione a Configuração de Segurança de Rede procurando por quaisquer elementos <pin-set>. Verifique suas datas de expiration, se houver. Se expirados, o certificate pinning será desativado para os domínios afetados.

Dica de Teste: Se uma verificação de validação de certificate pinning falhar, o seguinte evento deve ser registrado nos logs do sistema (consulte Monitoramento de Logs do Sistema):

I/X509Util: Failed to validate the certificate chain, error: Pin verification failed

TrustManager

A implementação de certificate pinning envolve três etapas principais:

  • Obter o certificado do(s) host(s) desejado(s).
  • Certificar-se de que o certificado está no formato .bks.
  • Vincular o certificado a uma instância do Apache Httpclient padrão.

Para analisar a implementação correta do certificate pinning, o cliente HTTP deve carregar o KeyStore:

InputStream in = resources.openRawResource(certificateRawResource);
keyStore = KeyStore.getInstance("BKS");
keyStore.load(resourceStream, password);

Uma vez que o KeyStore foi carregado, podemos usar o TrustManager que confia nas ACs em nosso KeyStore:

String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Criar um SSLContext que usa o TrustManager
// SSLContext context = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);

A implementação do app pode ser diferente, fazendo pinning apenas contra a chave pública do certificado, o certificado completo ou toda a cadeia de certificados.

Bibliotecas de Rede e WebViews

Aplicativos que usam bibliotecas de rede de terceiros podem utilizar a funcionalidade de certificate pinning das bibliotecas. Por exemplo, o okhttp pode ser configurado com o CertificatePinner da seguinte forma:

OkHttpClient client = new OkHttpClient.Builder()
        .certificatePinner(new CertificatePinner.Builder()
            .add("example.com", "sha256/UwQAapahrjCOjYI3oLUx5AQxPBR02Jz6/E2pt0IeLXA=")
            .build())
        .build();

Aplicativos que usam um componente WebView podem utilizar o manipulador de eventos do WebViewClient para algum tipo de "certificate pinning" de cada requisição antes do recurso de destino ser carregado. O código a seguir mostra um exemplo de verificação:

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient(){
    private String expectedIssuerDN = "CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US;";

    @Override
    public void onLoadResource(WebView view, String url)  {
        //Da documentação da API Android sobre "WebView.getCertificate()":
        //Obtém o certificado SSL para a página principal de nível superior
        //ou null se não houver certificado (o site não é seguro).
        //
        //Informações disponíveis na classe SslCertificate são "Issuer DN", "Subject DN" e auxiliares de data de validade
        SslCertificate serverCert = view.getCertificate();
        if(serverCert != null){
            //aplicar comparação de certificate ou public key pinning aqui
                //Lançar exceção para cancelar o carregamento do recurso...
            }
        }
    }
});

Alternativamente, é melhor usar um OkHttpClient com pins configurados e deixá-lo atuar como um proxy substituindo shouldInterceptRequest do WebViewClient.

Aplicativos Xamarin

Aplicativos desenvolvidos em Xamarin normalmente usarão ServicePointManager para implementar pinning.

Normalmente uma função é criada para verificar o(s) certificado(s) e retornar o valor booleano para o método ServerCertificateValidationCallback:

[Activity(Label = "XamarinPinning", MainLauncher = true)]
    public class MainActivity : Activity
    {
        // SupportedPublicKey - Valor hexadecimal da chave pública.
        // Use o método GetPublicKeyString() para determinar a chave pública do certificado que queremos fixar. Descomente o código de depuração na função ValidateServerCertificate uma primeira vez para determinar o valor a fixar.
        private const string SupportedPublicKey = "3082010A02820101009CD30CF05AE52E47B7725D3783B..."; // Reduzido para legibilidade

        private static bool ValidateServerCertificate(
                object sender,
                X509Certificate certificate,
                X509Chain chain,
                SslPolicyErrors sslPolicyErrors
            )
        {
            //Log.Debug("Xamarin Pinning",chain.ChainElements[X].Certificate.GetPublicKeyString());
            //return true;
            return SupportedPublicKey == chain.ChainElements[1].Certificate.GetPublicKeyString();
        }

        protected override void OnCreate(Bundle savedInstanceState)
        {
            System.Net.ServicePointManager.ServerCertificateValidationCallback += ValidateServerCertificate;
            base.OnCreate(savedInstanceState);
            SetContentView(Resource.Layout.Main);
            TesteAsync("https://security.claudio.pt");

        }

Neste exemplo particular estamos fixando a CA intermediária da cadeia de certificados. A saída da resposta HTTP estará disponível nos logs do sistema.

Um aplicativo Xamarin de exemplo com o exemplo anterior pode ser obtido no repositório MASTG

Após descompactar o arquivo APK, use um descompilador .NET como dotPeak, ILSpy ou dnSpy para descompilar os dlls do aplicativo armazenados dentro da pasta 'Assemblies' e confirmar o uso do ServicePointManager.

Saiba mais:

Aplicativos Cordova

Aplicativos híbridos baseados em Cordova não suportam Certificate Pinning nativamente, então plugins são usados para alcançar isso. O mais comum é o PhoneGap SSL Certificate Checker. O método check é usado para confirmar a fingerprint e callbacks determinarão os próximos passos.

  // Endpoint para verificar contra certificate pinning.
  var server = "https://www.owasp.org";
  // SHA256 Fingerprint (Pode ser obtido via "openssl s_client -connect hostname:443 | openssl x509 -noout -fingerprint -sha256"
  var fingerprint = "D8 EF 3C DF 7E F6 44 BA 04 EC D5 97 14 BB 00 4A 7A F5 26 63 53 87 4E 76 67 77 F0 F4 CC ED 67 B9";

  window.plugins.sslCertificateChecker.check(
          successCallback,
          errorCallback,
          server,
          fingerprint);

   function successCallback(message) {
     alert(message);
     // A mensagem é sempre: CONNECTION_SECURE.
     // Agora faça algo com o servidor confiável.
   }

   function errorCallback(message) {
     alert(message);
     if (message === "CONNECTION_NOT_SECURE") {
       // Provavelmente há um ataque MITM em andamento, tenha cuidado!
     } else if (message.indexOf("CONNECTION_FAILED") >- 1) {
       // Não havia conexão (ainda). A internet pode estar fora. Tente novamente (algumas vezes) após um pequeno timeout.
     }
   }

Após descompactar o arquivo APK, os arquivos Cordova/Phonegap estarão localizados na pasta /assets/www. A pasta 'plugins' dará visibilidade dos plugins usados. Precisaremos procurar por esses métodos no código JavaScript do aplicativo para confirmar seu uso.

Análise Dinâmica

Siga as instruções de Teste de Verificação de Identidade de Endpoint. Se isso não resultar no tráfego sendo proxyado, pode significar que o certificate pinning está realmente implementado e todas as medidas de segurança estão em vigor. O mesmo acontece para todos os domínios?

Como um teste rápido, você pode tentar contornar o certificate pinning usando objection conforme descrito em Contornando o Certificate Pinning. APIs relacionadas a pinning sendo hookadas pelo objection devem aparecer na saída do objection.

No entanto, tenha em mente que:

  • as APIs podem não estar completas.
  • se nada for hookado, isso não necessariamente significa que o aplicativo não implementa pinning.

Em ambos os casos, o aplicativo ou alguns de seus componentes podem implementar pinning personalizado de uma forma que é suportada pelo objection. Por favor, verifique a seção de análise estática para indicadores específicos de pinning e testes mais aprofundados.