简体   繁体   English

如何在Android上的loopj中支持Comodo SSL证书?

[英]How to support Comodo SSL cert in loopj on Android?

I'm running a site using HTTPS with an SSL cert from Comodo . 我正在使用带有Comodo的SSL证书的HTTPS运行网站。 Qualys gives an A+ score for the site and the same URL works without errors in Chrome on Android. Qualys对该网站给出了A +评分,并且相同的网址在Android上的Chrome浏览器中也不会出错。 When I try to connect to the site from an Android app using loopj, I get an SSLPeerUnverifiedException exception. 当我尝试使用loopj从Android应用程序连接到该站点时,出现SSLPeerUnverifiedException异常。 Do I have to manually provide certificate info? 我是否必须手动提供证书信息?

I see this behavior with the default AsyncHttpClient example: 我在默认的AsyncHttpClient示例中看到了此行为:

AsyncHttpClient client = new AsyncHttpClient();
client.get("https://myapp.com", new AsyncHttpResponseHandler() {

    @Override
    public void onStart() {
        // called before request is started
    }

    @Override
    public void onSuccess(int statusCode, Header[] headers, byte[] response) {
        // called when response HTTP status is "200 OK"
    }

    @Override
    public void onFailure(int statusCode, Header[] headers, byte[] errorResponse, Throwable e) {
        // called when response HTTP status is "4XX" (eg. 401, 403, 404)
    }

    @Override
    public void onRetry(int retryNo) {
        // called when request is retried
    }
});

Exception: 例外:

04-20 21:59:57.092: W/System.err(8824): javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
04-20 21:59:57.102: W/System.err(8824):     at com.android.org.conscrypt.SSLNullSession.getPeerCertificates(SSLNullSession.java:104)
04-20 21:59:57.102: W/System.err(8824):     at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:93)
04-20 21:59:57.102: W/System.err(8824):     at org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:388)
04-20 21:59:57.102: W/System.err(8824):     at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:214)
04-20 21:59:57.102: W/System.err(8824):     at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:167)
04-20 21:59:57.102: W/System.err(8824):     at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:125)
04-20 21:59:57.102: W/System.err(8824):     at org.apache.http.impl.client.DefaultRequestDirector.executeSB(DefaultRequestDirector.java:831)
04-20 21:59:57.102: W/System.err(8824):     at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:697)
04-20 21:59:57.102: W/System.err(8824):     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:575)
04-20 21:59:57.102: W/System.err(8824):     at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:491)
04-20 21:59:57.102: W/System.err(8824):     at com.loopj.android.http.AsyncHttpRequest.makeRequest(AsyncHttpRequest.java:147)
04-20 21:59:57.102: W/System.err(8824):     at com.loopj.android.http.AsyncHttpRequest.makeRequestWithRetries(AsyncHttpRequest.java:178)
04-20 21:59:57.102: W/System.err(8824):     at com.loopj.android.http.AsyncHttpRequest.run(AsyncHttpRequest.java:109)
04-20 21:59:57.102: W/System.err(8824):     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
04-20 21:59:57.102: W/System.err(8824):     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
04-20 21:59:57.102: W/System.err(8824):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
04-20 21:59:57.102: W/System.err(8824):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
04-20 21:59:57.102: W/System.err(8824):     at java.lang.Thread.run(Thread.java:818)

As an alternative to loopj, you can just create an AsyncTask that will perform the task on the program. 作为loopj的替代方法,您只需创建一个AsyncTask即可在程序上执行任务。 Almost the same way as loop is doing it. 几乎与循环相同。 I used the class below to perform HTTP/S request and it does the job. 我使用下面的类执行HTTP / S请求,它完成了这项工作。

class GetHTTPSTask extends AsyncTask<Void, Void, Boolean>
  {
    private String mUrl;

    public GetHTTPSTask(String url)
    {
      this.mUrl = url;
    }

    @Override
    protected Boolean doInBackground(Void... params)
    {
      try
      {
        URL urlConnection = new URL(mUrl);
        HttpURLConnection connection = (HttpURLConnection) urlConnection
          .openConnection();
        connection.setDoInput(true);
        connection.connect();
        InputStream input = connection.getInputStream();

        return Boolean.TRUE;
      }
      catch (Exception e)
      {
        e.printStackTrace();
      }
      return null;
    }
    @Override
    protected void onPostExecute(Boolean result)
    {
      if ( result != null)
      {
        // Connection was successful
        // Do something here
      }
      super.onPostExecute(result);
    }
  }

And to use it: 并使用它:

new GetHTTPSTask("https://www.google.com/").execute();

Turns out the server cannot rely on SNI if you're using Apache libraries. 事实证明,如果您使用的是Apache库,则服务器不能依赖SNI。

If you have control of the server, you can configure it have a unique IP. 如果可以控制服务器,则可以配置它具有唯一的IP。 Or, fix on the client: 或者,在客户端上修复:

From the Android docs : Android文档

Fortunately, HttpsURLConnection supports SNI since Android 2.3. 幸运的是,自Android 2.3起,HttpsURLConnection就支持SNI。 Unfortunately, Apache HTTP Client does not, which is one of the many reasons we discourage its use. 不幸的是,Apache HTTP Client却没有,这是我们不鼓励其使用的众多原因之一。 One workaround if you need to support Android 2.2 (and older) or Apache HTTP Client is to set up an alternative virtual host on a unique port so that it's unambiguous which server certificate to return. 如果您需要支持Android 2.2(或更旧版本)或Apache HTTP Client,一种解决方法是在唯一的端口上设置备用虚拟主机,以确保返回的服务器证书是明确的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM