web-dev-qa-db-ja.com

Https接続Android

Httpsの投稿を行っていますが、ssl exception Not Trusted server certificateの例外が発生しています。通常のhttpを実行すると、完全に正常に動作します。どういうわけか、サーバー証明書を受け入れる必要がありますか?

99
Sam97305421562

推測していますが、実際のハンドシェイクを行う場合は、Androidに証明書を知らせる必要があります。何でも受け入れたい場合は、この擬似コードを使用して、Apache HTTPクライアントで必要なものを取得します。

SchemeRegistry schemeRegistry = new SchemeRegistry ();

schemeRegistry.register (new Scheme ("http",
    PlainSocketFactory.getSocketFactory (), 80));
schemeRegistry.register (new Scheme ("https",
    new CustomSSLSocketFactory (), 443));

ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager (
    params, schemeRegistry);


return new DefaultHttpClient (cm, params);

CustomSSLSocketFactory:

public class CustomSSLSocketFactory extends org.Apache.http.conn.ssl.SSLSocketFactory
{
private SSLSocketFactory FACTORY = HttpsURLConnection.getDefaultSSLSocketFactory ();

public CustomSSLSocketFactory ()
    {
    super(null);
    try
        {
        SSLContext context = SSLContext.getInstance ("TLS");
        TrustManager[] tm = new TrustManager[] { new FullX509TrustManager () };
        context.init (null, tm, new SecureRandom ());

        FACTORY = context.getSocketFactory ();
        }
    catch (Exception e)
        {
        e.printStackTrace();
        }
    }

public Socket createSocket() throws IOException
{
    return FACTORY.createSocket();
}

 // TODO: add other methods like createSocket() and getDefaultCipherSuites().
 // Hint: they all just make a call to member FACTORY 
}

FullX509TrustManagerはjavax.net.ssl.X509TrustManagerを実装するクラスですが、どのメソッドも実際に作業を実行しないため、サンプル here を取得します。

幸運を!

45
Nate

これは私がやっていることです。証明書をもうチェックしません。

// always verify the Host - dont check for certificate
final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
};

/**
 * Trust every server - dont check for any certificate
 */
private static void trustAllHosts() {
    // Create a trust manager that does not validate certificate chains
    TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
        public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return new Java.security.cert.X509Certificate[] {};
        }

        public void checkClientTrusted(X509Certificate[] chain,
                String authType) throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] chain,
                String authType) throws CertificateException {
        }
    } };

    // Install the all-trusting trust manager
    try {
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(null, trustAllCerts, new Java.security.SecureRandom());
        HttpsURLConnection
                .setDefaultSSLSocketFactory(sc.getSocketFactory());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

そして

    HttpURLConnection http = null;

    if (url.getProtocol().toLowerCase().equals("https")) {
        trustAllHosts();
        HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
        https.setHostnameVerifier(DO_NOT_VERIFY);
        http = https;
    } else {
        http = (HttpURLConnection) url.openConnection();
    }
84
Ulrich Scheller

この質問に答えようとしている間に、より良いチュートリアルを見つけました。これにより、証明書のチェックを妥協する必要はありません。

http://blog.crazybob.org/2010/02/Android-trusting-ssl-certificates.html

*私はこれを書きませんでしたが、仕事のためにボブリーに感謝します

33
bajohns

クレイジーボブに非常によく似た私のブログ記事もご覧ください。

また、このソリューションは証明書のチェックを危険にさらすことはなく、独自のキーストアに信頼できる証明書を追加する方法を説明します。

http://blog.antoine.li/index.php/2010/10/Android-trusting-ssl-certificates/

6
saxos

http://madurangasblogs.blogspot.in/2013/08/avoiding-javaxnetsslsslpeerunverifiedex.html

礼儀マドゥランガ

Httpsを使用するアプリケーションを開発する場合、テストサーバーには有効なSSL証明書がありません。または、Webサイトが自己署名証明書を使用しているか、Webサイトが無料のSSL証明書を使用している場合があります。そのため、Apache HttpClientを使用してサーバーに接続しようとすると、「ピアが認証されていません」という例外を受け取ります。運用ソフトウェアのすべての証明書を信頼することはお勧めできませんが、状況に応じて信頼する必要があります。このソリューションは、「認証されていないピア」に起因する例外を解決します。

しかし、ソリューションに進む前に、本番アプリケーションにとってこれは良いアイデアではないことを警告する必要があります。これは、セキュリティ証明書を使用する目的に違反します。正当な理由がない限り、またはこれが問題を引き起こさないと確信している場合を除き、このソリューションを使用しないでください。

通常、このようなHttpClientを作成します。

HttpClient httpclient = new DefaultHttpClient();

ただし、HttpClientの作成方法を変更する必要があります。

まず、org.Apache.http.conn.ssl.SSLSocketFactoryを拡張するクラスを作成する必要があります。

import org.Apache.http.conn.ssl.SSLSocketFactory;
import Java.io.IOException;
import Java.net.Socket;
import Java.net.UnknownHostException;
import Java.security.KeyManagementException;
import Java.security.KeyStore;
import Java.security.KeyStoreException;
import Java.security.NoSuchAlgorithmException;
import Java.security.UnrecoverableKeyException;
import Java.security.cert.CertificateException;
import Java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class MySSLSocketFactory extends SSLSocketFactory {
         SSLContext sslContext = SSLContext.getInstance("TLS");

    public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
        super(truststore);

        TrustManager tm = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };

        sslContext.init(null, new TrustManager[] { tm }, null);
    }

    @Override
    public Socket createSocket(Socket socket, String Host, int port, boolean autoClose) throws IOException, UnknownHostException {
        return sslContext.getSocketFactory().createSocket(socket, Host, port, autoClose);
    }

    @Override
    public Socket createSocket() throws IOException {
        return sslContext.getSocketFactory().createSocket();
    }
}

次に、このようなメソッドを作成します。

public HttpClient getNewHttpClient() {
     try {
         KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
         trustStore.load(null, null);

         SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
         sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

         HttpParams params = new BasicHttpParams();
         HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
         HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

         SchemeRegistry registry = new SchemeRegistry();
         registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
         registry.register(new Scheme("https", sf, 443));

         ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

         return new DefaultHttpClient(ccm, params);
     } catch (Exception e) {
         return new DefaultHttpClient();
     }
}

その後、HttpClientを作成できます。

HttpClient httpclient = getNewHttpClient();

ログインページに投稿リクエストを送信しようとしている場合、残りのコードは次のようになります。

private URI url = new URI("url of the action of the form");
HttpPost httppost =  new HttpPost(url);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();  
nameValuePairs.add(new BasicNameValuePair("username", "user"));  
nameValuePairs.add(new BasicNameValuePair("password", "password"));
try {
    httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
    HttpResponse response = httpclient.execute(httppost);
    HttpEntity entity = response.getEntity();
    InputStream is = entity.getContent();
} catch (UnsupportedEncodingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (ClientProtocolException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

InputStreamへのhtmlページを取得します。その後、返されたhtmlページで何でもできます。

しかし、ここでは問題に直面します。 Cookieを使用してセッションを管理する場合は、この方法で管理することはできません。 Cookieを取得する場合は、ブラウザーを介して取得する必要があります。その後、あなただけがクッキーを受け取ります。

4
Rohit Mandiwal

StartSSLまたはThawte証明書を使用している場合、Froyo以前のバージョンでは失敗します。すべての証明書を信頼する代わりに、 新しいバージョンのCAcertリポジトリ を使用できます。

3
Juan Sánchez

これらのどれも私にとってはうまくいきませんでした( Thawte bug によって悪化しました)。最終的には Androidでの自己署名SSL受け入れ および カスタムSSL処理がAndroid 2.2 FroYoで機能しなくなりました で修正されました

2
Adrian Spinei

この答えは私にはうまくいきませんでしたので、ここに証明書を信頼するコードがあります。

import Java.io.IOException;

    import Java.net.Socket;
    import Java.security.KeyManagementException;
    import Java.security.KeyStoreException;
    import Java.security.NoSuchAlgorithmException;
    import Java.security.UnrecoverableKeyException;
    import Java.security.cert.CertificateException;
    import Java.security.cert.X509Certificate;

    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;

    import org.Apache.http.client.ClientProtocolException;
    import org.Apache.http.client.HttpClient;
    import org.Apache.http.client.methods.HttpPost;
    import org.Apache.http.conn.scheme.PlainSocketFactory;
    import org.Apache.http.conn.scheme.Scheme;
    import org.Apache.http.conn.scheme.SchemeRegistry;
    import org.Apache.http.conn.ssl.SSLSocketFactory;
    import org.Apache.http.conn.ssl.X509HostnameVerifier;
    import org.Apache.http.impl.client.DefaultHttpClient;
    import org.Apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
    import org.Apache.http.params.BasicHttpParams;
import org.Apache.http.params.HttpConnectionParams;
import org.Apache.http.params.HttpParams;

    public class HttpsClientBuilder {
        public static DefaultHttpClient getBelieverHttpsClient() {

            DefaultHttpClient client = null;

            SchemeRegistry Current_Scheme = new SchemeRegistry();
            Current_Scheme.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            try {
                Current_Scheme.register(new Scheme("https", new Naive_SSLSocketFactory(), 8443));
            } catch (KeyManagementException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (UnrecoverableKeyException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (KeyStoreException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            HttpParams Current_Params = new BasicHttpParams();
            int timeoutConnection = 8000;
            HttpConnectionParams.setConnectionTimeout(Current_Params, timeoutConnection);
            int timeoutSocket = 10000;
            HttpConnectionParams.setSoTimeout(Current_Params, timeoutSocket);
            ThreadSafeClientConnManager Current_Manager = new ThreadSafeClientConnManager(Current_Params, Current_Scheme);
            client = new DefaultHttpClient(Current_Manager, Current_Params);
            //HttpPost httpPost = new HttpPost(url);
            //client.execute(httpPost);

         return client;
         }

    public static class Naive_SSLSocketFactory extends SSLSocketFactory
    {
        protected SSLContext Cur_SSL_Context = SSLContext.getInstance("TLS");

        public Naive_SSLSocketFactory ()
                throws NoSuchAlgorithmException, KeyManagementException,
                KeyStoreException, UnrecoverableKeyException
        {
            super(null, null, null, null, null, (X509HostnameVerifier)null);
            Cur_SSL_Context.init(null, new TrustManager[] { new X509_Trust_Manager() }, null);
        }

        @Override
        public Socket createSocket(Socket socket, String Host, int port,
                boolean autoClose) throws IOException
        {
            return Cur_SSL_Context.getSocketFactory().createSocket(socket, Host, port, autoClose);
        }

        @Override
        public Socket createSocket() throws IOException
        {
            return Cur_SSL_Context.getSocketFactory().createSocket();
        }
    }

    private static class X509_Trust_Manager implements X509TrustManager
    {

        public void checkClientTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
            // TODO Auto-generated method stub

        }

        public void checkServerTrusted(X509Certificate[] chain, String authType)
                throws CertificateException {
            // TODO Auto-generated method stub

        }

        public X509Certificate[] getAcceptedIssuers() {
            // TODO Auto-generated method stub
            return null;
        }

    };
}
2
Speise

これは、Android 2.xの既知の問題です。この問題に1週間苦労していましたが、次の質問に出くわしました。これは問題の良い背景を提供するだけでなく、セキュリティホールのない実用的かつ効果的なソリューションを提供します。

Android 2.3に「ピア証明書なし」エラーがありますが、4にはありません

1
alumat

SSL証明書のAndroidの詳細については知りませんが、Androidが自己署名SSL証明書をすぐに受け入れないことは理にかなっています。同じ問題に対処していると思われるAndroidフォーラムからこの投稿を見つけました: http://androidforums.com/Android-applications/950-imap-self-signed-ssl-certificates。 html

1
Matti Lyra

なんらかの理由で、上記のhttpClientについて説明した解決策がうまくいきませんでした。最後に、カスタムSSLSocketFactoryクラスを実装するときにメソッドを正しくオーバーライドすることで、それを機能させることができました。

@Override
public Socket createSocket(Socket socket, String Host, int port, boolean autoClose) 
                              throws IOException, UnknownHostException 
    {
    return sslFactory.createSocket(socket, Host, port, autoClose);
}

@Override
public Socket createSocket() throws IOException {
    return sslFactory.createSocket();
}

これは私にとって完璧に働いた方法です。次のスレッドで完全なカスタムクラスと実装を確認できます。 http://blog.syedgakbar.com/2012/07/21/Android-https-and-not-trusted-server-certificate-error/

0

AWS Apacheサーバーで自己署名証明書を使用し、AndroidデバイスからHttpsURLConnectionに接続するのに役立つソース:

awsインスタンスのSSL -SSLのAmazonチュートリアル
HTTPSおよびSSLを使用したAndroidセキュリティ -証明書を受け入れるために、クライアント上で独自のトラストマネージャーを作成します
自己署名証明書の作成 -証明書を作成するための簡単なスクリプト

その後、私は次のことをしました:

  1. サーバーがhttpsをサポートしていることを確認しました(Sudo yum install -y mod24_ssl)
  2. このスクリプトをファイルcreate_my_certs.shに配置します。
#!/bin/bash
FQDN=$1

# make directories to work from
mkdir -p server/ client/ all/

# Create your very own Root Certificate Authority
openssl genrsa \
  -out all/my-private-root-ca.privkey.pem \
  2048

# Self-sign your Root Certificate Authority
# Since this is private, the details can be as bogus as you like
openssl req \
  -x509 \
  -new \
  -nodes \
  -key all/my-private-root-ca.privkey.pem \
  -days 1024 \
  -out all/my-private-root-ca.cert.pem \
  -subj "/C=US/ST=Utah/L=Provo/O=ACME Signing Authority Inc/CN=example.com"

# Create a Device Certificate for each domain,
# such as example.com, *.example.com, awesome.example.com
# NOTE: You MUST match CN to the domain name or ip address you want to use
openssl genrsa \
  -out all/privkey.pem \
  2048

# Create a request from your Device, which your Root CA will sign
openssl req -new \
  -key all/privkey.pem \
  -out all/csr.pem \
  -subj "/C=US/ST=Utah/L=Provo/O=ACME Tech Inc/CN=${FQDN}"

# Sign the request from Device with your Root CA
openssl x509 \
  -req -in all/csr.pem \
  -CA all/my-private-root-ca.cert.pem \
  -CAkey all/my-private-root-ca.privkey.pem \
  -CAcreateserial \
  -out all/cert.pem \
  -days 500

# Put things in their proper place
rsync -a all/{privkey,cert}.pem server/
cat all/cert.pem > server/fullchain.pem         # we have no intermediates in this case
rsync -a all/my-private-root-ca.cert.pem server/
rsync -a all/my-private-root-ca.cert.pem client/
  1. bash create_my_certs.sh yourdomain.comを実行します
  2. サーバー上の適切な場所に証明書を配置します(設定は/etc/httpd/conf.d/ssl.confにあります)。これらはすべて設定する必要があります。
    SSLCertificateFile
    SSLCertificateKeyFile
    SSLCertificateChainFile
    SSLCACertificateFile

  3. Sudo service httpd restartを使用してhttpdを再起動し、httpdが起動していることを確認します。
    httpdの停止:[OK]
    httpdの起動:[OK]

  4. my-private-root-ca.certをAndroidプロジェクトアセットフォルダーにコピーします

  5. トラストマネージャーを作成します。

    SSLContext SSLContext;

    CertificateFactory cf = CertificateFactory.getInstance( "X.509"); InputStream caInput = context.getAssets()。open( "my-private-root-ca.cert.pem");証明書ca; try {ca = cf.generateCertificate(caInput); }最後に{caInput.close(); }

      // Create a KeyStore containing our trusted CAs
      String keyStoreType = KeyStore.getDefaultType();
      KeyStore keyStore = KeyStore.getInstance(keyStoreType);
      keyStore.load(null, null);
      keyStore.setCertificateEntry("ca", ca);
    
      // Create a TrustManager that trusts the CAs in our KeyStore
      String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
      TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
      tmf.init(keyStore);
    
      // Create an SSLContext that uses our TrustManager
      SSLContext = SSLContext.getInstance("TLS");
      SSSLContext.init(null, tmf.getTrustManagers(), null);
    
  6. そして、HttpsURLConnectionを使用して接続を確立します。

    HttpsURLConnection connection =(HttpsURLConnection)url.openConnection(); connection.setSSLSocketFactory(SSLContext.getSocketFactory());

  7. それで、https接続を試してください。

0
MikeL

このクラスを作成して見つけました

package com.example.fakessl;

import Java.security.KeyManagementException;
import Java.security.NoSuchAlgorithmException;
import Java.security.SecureRandom;
import Java.security.cert.CertificateException;
import Java.security.cert.X509Certificate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;

import Android.util.Log;

public class CertificadoAceptar {
    private static TrustManager[] trustManagers;

    public static class _FakeX509TrustManager implements
            javax.net.ssl.X509TrustManager {
        private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[] {};

        public void checkClientTrusted(X509Certificate[] arg0, String arg1)
                throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] arg0, String arg1)
                throws CertificateException {
        }

        public boolean isClientTrusted(X509Certificate[] chain) {
            return (true);
        }

        public boolean isServerTrusted(X509Certificate[] chain) {
            return (true);
        }

        public X509Certificate[] getAcceptedIssuers() {
            return (_AcceptedIssuers);
        }
    }

    public static void allowAllSSL() {

        javax.net.ssl.HttpsURLConnection
                .setDefaultHostnameVerifier(new HostnameVerifier() {
                    public boolean verify(String hostname, SSLSession session) {
                        return true;
                    }
                });

        javax.net.ssl.SSLContext context = null;

        if (trustManagers == null) {
            trustManagers = new javax.net.ssl.TrustManager[] { new _FakeX509TrustManager() };
        }

        try {
            context = javax.net.ssl.SSLContext.getInstance("TLS");
            context.init(null, trustManagers, new SecureRandom());
        } catch (NoSuchAlgorithmException e) {
            Log.e("allowAllSSL", e.toString());
        } catch (KeyManagementException e) {
            Log.e("allowAllSSL", e.toString());
        }
        javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(context
                .getSocketFactory());
    }
}

あなたのコードは白これ

CertificadoAceptar ca = new CertificadoAceptar();
ca.allowAllSSL();
HttpsTransportSE Transport = new HttpsTransportSE("iphost or Host name", 8080, "/WS/wsexample.asmx?WSDL", 30000);
0
Erick Guardado