android中的https(无对等证书)问题

Posted

技术标签:

【中文标题】android中的https(无对等证书)问题【英文标题】:Problems with https (No peer certificate) in android 【发布时间】:2012-03-02 10:27:54 【问题描述】:

问题

我想将 https 请求发送到我自己的服务器 https://10.2.20.20/fido/EzPay/login.php 站点并从它获取响应并将其保存在例如字符串中。我在互联网上找到了一些示例代码并尝试测试它们以解决我的问题,但它们没有帮助。下面我介绍我测试过的部分代码。


代码示例:

我尝试了这段代码,但我总是得到同样的异常“没有对等证书”为什么?

try

    HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

    DefaultHttpClient client = new DefaultHttpClient();

    SchemeRegistry registry = new SchemeRegistry();
    SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
    socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
    registry.register(new Scheme("https", socketFactory, 443));
    SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
    DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());

    // Set verifier      
    HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

    // Example send http request
    final String url = "https://10.2.20.20/fido/EzPay/login.php";
    HttpPost httpPost = new HttpPost(url);
    HttpResponse response = httpClient.execute(httpPost);

    BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
    String line = "";
    while ((line = rd.readLine()) != null) 
        Log.i(DownloadImageTask.class.getName(), line);
    


catch(IOException ex)

    Log.e(DownloadImageTask.class.getName(), ex.getMessage());

例外。

03-02 16:58:25.234: W/System.err(1868): javax.net.ssl.SSLPeerUnverifiedException:没有对等证书 03-02 16:58:25.238:W/System.err(1868):在 org.apache.harmony.xnet.provider.jsse.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:137) 03-02 16:58:25.238: W/System.err(1868): 在 org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:93) 03-02 16:58:25.238: W/System.err(1868): 在 org.apache.http.conn.ssl.SSLSocketFactory.createSocket(SSLSocketFactory.java:381) 03-02 16:58:25.238: W/System.err(1868): 在 org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:165) 03-02 16:58:25.250: W/System.err(1868): 在 org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:164) 03-02 16:58:25.250: W/System.err(1868): 在 org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:119) 03-02 16:58:25.250: W/System.err(1868): 在 org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:360) 03-02 16:58:25.250: W/System.err(1868): 在 org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:555) 03-02 16:58:25.250: W/System.err(1868): 在 org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:487) 03-02 16:58:25.250: W/System.err(1868): 在 org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:465) 03-02 16:58:25.250: W/System.err(1868): 在 com.https.test.DownloadImageTask.doInBackground(Https_testActivity.java:78) 03-02 16:58:25.250: W/System.err(1868): 在 com.https.test.DownloadImageTask.doInBackground(Https_testActivity.java:1) 03-02 16:58:25.250: W/System.err(1868): 在 android.os.AsyncTask$2.call(AsyncTask.java:264) 03-02 16:58:25.253: W / System.err(1868):在 java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 03-02 16:58:25.253: W/System.err(1868): 在 java.util.concurrent.FutureTask.run(FutureTask.java:137) 03-02 16:58:25.253:W/System.err(1868):在 android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208) 03-02 16:58:25.257:W/System.err(1868):在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 03-02 16:58:25.257: W/System.err(1868): 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 03-02 16:58:25.257: W/System.err(1868): 在 java.lang.Thread.run(Thread.java:856)


问题

我做错了什么以及如何解决这个问题。为什么我得到“没有对等证书”异常?

谢谢。

已编辑


Windows 服务器设置。

<VirtualHost *:443>
  ServerName 10.2.20.20

 Alias /fido/EzPay/ "d:/fido/EzPay/" 
Alias /fido/EzPay "d:/fido/EzPay/" 

<Directory "d:/fido/EzPay/">
    Options Indexes FollowSymLinks MultiViews
    AllowOverride all
        Order allow,deny
    Allow from all
</Directory>


  # These are the actual SSL directives needed to get it all working!
  SSLEngine on
  SSLCertificateFile C:/wamp/bin/apache/apache2.2.17/conf/ssl/fidoserver.crt
  SSLCertificateKeyFile C:/wamp/bin/apache/apache2.2.17/conf/ssl/fidoserver.pem
</VirtualHost>

【问题讨论】:

您如何运行响应变量而不是缓冲阅读器?你用过WebView吗?你可以分享代码吗?我被困在这个问题上好几天了,没有正确的答案可以帮助我。 @MelvinLai 您必须仅在我的应用程序开始工作的情况下使用密钥库。 How do I avoid getting "No peer certificate" error when connecting to this HTTPS site on Android?的可能重复 【参考方案1】:

终于解决了 https 问题。当我战斗时,主要问题出在服务器上,特别是在证书上。 Android 仅支持“BKS”证书,这就是我们无法得到响应的原因 服务器。为了解决这个问题,我阅读了 30 多篇文章,终于找到了解决方案。

我为解决此问题所做的步骤如下所示:

我做的第一件事是从我们的 fidoserver.crt 证书生成 .bks 密钥库文件,为此我已经阅读了这篇文章并执行以下操作:

    打开cmd 转到 JDK 文件夹“cd X:\Programs\Java\Jdk6\bin” 调用以下命令:

keytool -import -alias tomcat -file X://KeyStore/fidoserver.crt -keypass 密码 -keystore X://KeyStore/keystore.bks -storetype BKS -storepass 222222 -providerClass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath X://KeyStore/bcprov-jdk16-146.jar

在运行此命令之前,我已下载 Bouncy Castle .jar 文件并将其放入带有证书的文件夹中。完成所有步骤后,我得到了 keystore.bks 文件,它是 Android 应用程序的正确证书文件。我把这个文件放在 Androids mnc/sdcard 文件夹中。在 java 代码中,我编写了以下代码来读取该 keystore.bbk 文件

KeyStore trustStore  = KeyStore.getInstance( "BKS" /*KeyStore.getDefaultType()*/ );
FileInputStream instream = new FileInputStream(new File("/mnt/sdcard/keystore.bks"));
try 
    trustStore.load(instream, "222222".toCharArray());
 catch (NoSuchAlgorithmException e) 
    e.printStackTrace();
 catch (CertificateException e) 
    e.printStackTrace();
 catch (IOException e) 
    e.printStackTrace();
 finally 
    try  instream.close();  catch (Exception ignore) 


// Create socket factory with given keystore.
SSLSocketFactory socketFactory = new SSLSocketFactory(trustStore);

SSLSocketFactory socketFactory = new SSLSocketFactory(trustStore);
Scheme sch = new Scheme("https", socketFactory, 443);
httpclient.getConnectionManager().getSchemeRegistry().register(sch);

HttpGet httpget = new HttpGet("https://10.2.20.20/fido/EzPay/login.php");

System.out.println("executing request " + httpget.getRequestLine());

HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();

System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) 
    System.out.println("Response content length:  " + entity.getContentLength());

            
// Print html.
BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = in.readLine()) != null) 
     System.out.println(line);

in.close();

这一切都允许 m 使用给定的密码 222222(我们在使用 keytool 创建密钥库时提供的密码)加载我们的证书。

在此之后,我的所有测试应用程序都开始正常工作。现在我可以向 https 发送请求并获得响应。我已经测试过了 使用 FIDO 服务器的应用程序,一切正常!我想周一我会对 EzPay 应用程序和它进行一些更改 将开始使用 https 连接。

参考文献

Using TLS with Apache Tomcat and Android SSL Verification for Android Applications KeyStore Android: Trusting SSL certificates Bouncy Castle Android/Java — How to Create HTTPS Connection?

【讨论】:

这个步骤看起来很有说服力,但是我卡在 KeyStore 步骤,当我键入命令行时,我真的需要在我的文件夹中拥有证书本身吗?有没有办法可以与您交流而不是在这里发表评论?我有一个Skype帐户,我真的很想解决这个问题。由于我在Android上很弱,所以完成时间太长了 我关注了blog.antoine.li/2010/10/22/android-trusting-ssl-certificates,您也参考了它。新的 httpclient 类适用于 http 连接,但对于 https 它仍然给我“无对等证书”异常。遵循您的示例后有什么想法可能是什么问题? @ViToBrothers 嗨,如果我想相互验证,我需要将客户端证书放入 bks 文件中吗?【参考方案2】:

请求方法POST不适合URL /。这就是我们所知道的。

示例 1 不起作用,因为您似乎不允许向该页面发送 POST 请求。试试:

/* ... */
HttpGet httpGet = new HttpGet(url);
HttpResponse response = httpClient.execute(httpGet);
/* ... */

示例2不起作用,因为您不接受网站证书作为接受的证书,所以它也应该是这样的:

/* ... */
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());
/* ... */

【讨论】:

给我10分钟,我会尽力让你知道的。 +1 是的,你是对的,我通过示例 1 访问了encrypted.google.com,现在我修改代码并在本地服务器 https:\\10.1.20.20\login.php 上提供我自己的 url 作为 url,但是我收到异常“没有对等证书”我的服务器或应用程序有什么问题? 如果它适用于 google 而不适用于您的服务器,则意味着您没有在服务器上正确配置 SSL。如果您使用的是 Apache 服务器,请检查:informit.com/articles/article.aspx?p=30115&seqNum=5 所以你认为主要问题是服务器配置?? 我对 Windows Server 一无所知。我对此无能为力。您可以尝试将其作为一个单独的问题提出。【参考方案3】:

您是否尝试过使用浏览器打开页面?如果它没有打开你的配置是错误的。

请注意,如果您使用自签名证书,您可能会遇到一些连接问题。某些 Android 内核版本(2.6.32.9 之前)不喜欢 Self-Singed-Certificates。

【讨论】:

我尝试通过浏览器打开,它运行良好,但我仍然无法通过我的应用程序打开。 :( Android 版本 4.0.3 内核版本 3.0.8-gb55e9ac,NexusS

以上是关于android中的https(无对等证书)问题的主要内容,如果未能解决你的问题,请参考以下文章

Android L - 没有对等证书

Android ssl:javax.net.ssl.SSLPeerUnverifiedException:没有对等证书(又一次)

Android:对于套接字,传递“对等方的证书与预期的主机名不匹配”错误的最安全方法?

如何在Android上进行SSL对等验证工作?

SSL:无法从对等证书中获取公用名

主机名与对等方提供的证书主题不匹配,但完全匹配