跳过内容

MASTG-TEST-0022:测试自定义证书存储和证书锁定

已弃用测试

此测试已**弃用**,不应再使用。**原因**:MASTG V2 中提供新版本

请查看以下涵盖此 v1 测试的 MASTG v2 测试

概述

静态分析

网络安全配置

检查网络安全配置,查找任何 <pin-set> 元素。检查它们的 expiration 日期(如果有)。如果过期,证书锁定将对受影响的域禁用。

测试提示:如果证书锁定验证检查失败,则应在系统日志中记录以下事件(请参阅 监控系统日志)

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

TrustManager

实施证书锁定涉及三个主要步骤

  • 获取所需主机的证书。
  • 确保证书为 .bks 格式。
  • 将证书锁定到默认 Apache Httpclient 的实例。

为了分析证书锁定的正确实施,HTTP 客户端应加载 KeyStore

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

加载 KeyStore 后,我们可以使用 TrustManager,它信任我们的 KeyStore 中的 CA

String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses the TrustManager
// SSLContext context = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);

应用的实施方式可能不同,仅针对证书的公钥、整个证书或整个证书链进行锁定。

网络库和 WebViews

使用第三方网络库的应用程序可能会利用这些库的证书锁定功能。例如,可以使用 CertificatePinner 设置 okhttp

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

使用 WebView 组件的应用程序可能会使用 WebViewClient 的事件处理程序,对每个请求进行某种“证书锁定”,然后再加载目标资源。以下代码显示了一个验证示例

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)  {
        //From Android API documentation about "WebView.getCertificate()":
        //Gets the SSL certificate for the main top-level page
        //or null if there is no certificate (the site is not secure).
        //
        //Available information on SslCertificate class are "Issuer DN", "Subject DN" and validity date helpers
        SslCertificate serverCert = view.getCertificate();
        if(serverCert != null){
            //apply either certificate or public key pinning comparison here
                //Throw exception to cancel resource loading...
            }
        }
    }
});

或者,最好使用配置了锁定的 OkHttpClient,并让它作为代理覆盖 WebViewClientshouldInterceptRequest

Xamarin 应用程序

使用 Xamarin 开发的应用程序通常会使用 ServicePointManager 来实施锁定。

通常会创建一个函数来检查证书,并将布尔值返回给 ServerCertificateValidationCallback 方法

[Activity(Label = "XamarinPinning", MainLauncher = true)]
    public class MainActivity : Activity
    {
        // SupportedPublicKey - Hexadecimal value of the public key.
        // Use GetPublicKeyString() method to determine the public key of the certificate we want to pin. Uncomment the debug code in the ValidateServerCertificate function a first time to determine the value to pin.
        private const string SupportedPublicKey = "3082010A02820101009CD30CF05AE52E47B7725D3783B..."; // Shortened for readability

        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");

        }

在这个特定示例中,我们锁定了证书链的中间 CA。HTTP 响应的输出将在系统日志中可用。

可以在 MASTG 存储库中获取包含前面示例的示例 Xamarin 应用

解压缩 APK 文件后,使用像 dotPeak、ILSpy 或 dnSpy 这样的 .NET 反编译器来反编译存储在“Assemblies”文件夹中的应用 dll,并确认 ServicePointManager 的使用情况。

了解更多

Cordova 应用程序

基于 Cordova 的混合应用程序本身不支持证书锁定,因此使用插件来实现此目的。最常见的是 PhoneGap SSL 证书检查器check 方法用于确认指纹,回调将确定后续步骤。

  // Endpoint to verify against certificate pinning.
  var server = "https://www.owasp.org";
  // SHA256 Fingerprint (Can be obtained 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);
     // Message is always: CONNECTION_SECURE.
     // Now do something with the trusted server.
   }

   function errorCallback(message) {
     alert(message);
     if (message === "CONNECTION_NOT_SECURE") {
       // There is likely a MITM attack going on, be careful!
     } else if (message.indexOf("CONNECTION_FAILED") >- 1) {
       // There was no connection (yet). Internet may be down. Try again (a few times) after a little timeout.
     }
   }

解压缩 APK 文件后,Cordova/Phonegap 文件将位于 /assets/www 文件夹中。“plugins”文件夹将使您可以看到使用的插件。我们需要在应用程序的 JavaScript 代码中搜索此方法以确认其使用情况。

动态分析

按照 测试端点身份验证 中的说明进行操作。如果这样做不会导致流量被代理,则可能意味着实际上实施了证书锁定,并且所有安全措施都已到位。对于所有域是否都发生同样的情况?

作为快速冒烟测试,您可以尝试使用 objection 中描述的 绕过证书锁定 来绕过证书锁定。objection 挂钩的锁定相关 API 应该出现在 objection 的输出中。

但是,请记住

  • API 可能不完整。
  • 如果没有挂钩任何内容,并不一定意味着应用程序未实施锁定。

在这两种情况下,应用程序或其某些组件可能以一种 objection 支持的方式实施自定义锁定。请查看静态分析部分以获取特定的锁定指示器和更深入的测试。