使用 Google Volley 进行 SSL 固定

Posted

技术标签:

【中文标题】使用 Google Volley 进行 SSL 固定【英文标题】:SSL Pinning using Google Volley 【发布时间】:2018-01-17 11:24:24 【问题描述】:

我的问题是通过提及我迄今为止尝试过的内容来开始我的问题:

我的应用程序中没有证书,我只使用 SHA256 密钥,互联网上的大多数答案都需要应用程序中的物理证书才能将其加载到密钥库中,我没有。

我收到以下错误:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

1)TrustKit 它需要编译 SDK 24 及更高版本,但我有 23 个并且很多支持库与 SDK 23 同步,所以我无法更改所有这些,它可能会在某个时候使我的应用程序崩溃。

2)CWAC-NetSecurity 我已经在我的代码中实现了这一点,而没有使用 android N 安全设置,我也遵循了 git 页面上给出的指令,但无法从中将 sslSocketfactory 传递给 Volley,它有 OkHTTP 的示例。所以它也给出了上述错误。

我已经用 OKHttp 的 CertificatePinner 进行了尝试,但它也不适合我。同样的错误。我也尝试将 hostNameVerifier 和 sslSocketFactory 传递给 HttpsUrlConnection 但同样的错误。

JsonObjectRequestSolaire jsonRequest = new JsonObjectRequestSolaire(method, URL, object, headers, responseListener, errorListener);
    RetryPolicy policy = new DefaultRetryPolicy(TIMEOUT, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
    jsonRequest.setRetryPolicy(policy);
    jsonRequest.setShouldCache(false);

    OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .certificatePinner(new CertificatePinner.Builder()
                    .add("my_domain", "sha256/shaKey")//example.com
                    .add("my_domain", "sha256/shaKey")//also tried *.example.com
                    .build())
            .build();

    //HttpsURLConnection.setDefaultHostnameVerifier(okHttpClient.hostnameVerifier());
    //HttpsURLConnection.setDefaultSSLSocketFactory(okHttpClient.sslSocketFactory());

    RequestQueue requestQueue = Volley.newRequestQueue(activity.getApplicationContext(), new HurlStack(null, okHttpClient.sslSocketFactory()));
    requestQueue.add(jsonRequest);

通过使用我们的 ios 开发人员实现的 trustKit,它对他有用。

提前致谢。

请在此处分享您的宝贵意见,以便我了解 SSL 固定概念。

【问题讨论】:

使用的服务器证书是否有效?固定意味着定期证书检查 + 固定根证书、中间证书或离开证书。顺便说一句:如果你有 sha256 哈希和域名,你可以简单地从服务器下载证书,验证它是否正确。 也检查this link。 也检查this,可能是CA的问题。 【参考方案1】:

使用这个 VolleySingleton:

public class VolleySingleton 


  private static VolleySingleton mInstance;
  private RequestQueue mRequestQueue;
  private static Context mCtx;

  private VolleySingleton(Context context) 
    mCtx = context;
    mRequestQueue = getRequestQueue();
  

  public static synchronized VolleySingleton getInstance(Context context) 
    if (mInstance == null) 
      mInstance = new VolleySingleton(context);
    
    return mInstance;
  

  public RequestQueue getRequestQueue() 
    if (mRequestQueue == null) 
      // getApplicationContext() is key, it keeps you from leaking the
      // Activity or BroadcastReceiver if someone passes one in.
      mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext(), new HurlStack(null, newSslSocketFactory()));
    
    return mRequestQueue;
  

  public <T> void addToRequestQueue(Request<T> req) 
    int socketTimeout = 90000;
    RetryPolicy policy = new DefaultRetryPolicy(socketTimeout,
        DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
        DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
    req.setRetryPolicy(policy);
    getRequestQueue().add(req);
  

  private SSLSocketFactory newSslSocketFactory() 
    try 
      // Get an instance of the Bouncy Castle KeyStore format
      KeyStore trusted = KeyStore.getInstance("BKS");
      // Get the raw resource, which contains the keystore with
      // your trusted certificates (root and any intermediate certs)
      InputStream in = mCtx.getApplicationContext().getResources().openRawResource(R.raw.trusted);
      try 
        // Initialize the keystore with the provided trusted certificates
        // Provide the password of the keystore
        trusted.load(in, mCtx.getString(R.string.KEYSTORE_PASS).toCharArray());
       finally 
        in.close();
      

      String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
      TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
      tmf.init(trusted);

      SSLContext context = SSLContext.getInstance("TLSv1.2");
      context.init(null, tmf.getTrustManagers(), null);

      HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() 
        @Override
        public boolean verify(String hostname, SSLSession session) 
          Log.i("Volley","Verifing host:"+hostname);
          return true;
        
      );

      SSLSocketFactory sf = context.getSocketFactory();
      return sf;
     catch (Exception e) 
      throw new AssertionError(e);
    
  

【讨论】:

以上是关于使用 Google Volley 进行 SSL 固定的主要内容,如果未能解决你的问题,请参考以下文章

Android 开源框架 ( 六 ) Volley --- Google的轻量级网络通信框架

com.android.volley.NoConnectionError:javax.net.ssl.SSLHandshakeException:javax.net.ssl.SSLProtocolEx

为啥 Volley 回退到 SSLV3?

Volley源码解析

Volley源码解析

带有经过身份验证的 Appengine 端点的 Google Volley 库?