web-dev-qa-db-ja.com

Android SSL HttpGet(ピア証明書なし)エラーOR(ピアにより接続が閉じられました)エラー

私は単純なHttpGetを実行してWebページを読み込もうとしています。私はこれをiOSで動作させ、http =ではなくAndroidで動作していますが、httpsでは動作していません。

Urlは内部ネットワークIPおよびカスタムポートなので、_http://ipaddress:port/MyPage.html_のパスを使用してこのようなhttpで読み取ることができます

_HttpClient httpclient = new DefaultHttpClient(httpParameters);
                    HttpResponse response;
        String responseString = null;
        try {
            // Try connection
            HttpGet get = new HttpGet(params[0].path);
            get.addHeader("Authorization",
                    "Basic "
                            + Base64.encodeBytes(new String(params[0].username + ":" + params[0].password)
                                    .getBytes()));
        response = httpclient.execute(get);
        StatusLine statusLine = response.getStatusLine();
        if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            response.getEntity().writeTo(out);
            out.close();
            responseString = out.toString();
        } else {
            // Closes the connection.
            response.getEntity().getContent().close();
            throw new IOException(statusLine.getReasonPhrase());
        }
    } catch (ClientProtocolException e) {
        Log.e(TAG, "ClientProtocolException");
        this.e = e;
    } catch (IOException e) {
        Log.e(TAG, "IOException");
        this.e = e;
    }
    return responseString;
_

Httpsを使用しようとすると、_No peer certificate_エラーが表示されます。だから私はこのコードを使用してみました:HttpClient httpclient = new DefaultHttpClient(httpParameters);

_private HttpClient createHttpClient() {
        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.DEFAULT_CONTENT_CHARSET);
            HttpProtocolParams.setUseExpectContinue(params, true);

            SchemeRegistry schReg = new SchemeRegistry();
            schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            schReg.register(new Scheme("https", sf, 8080));
            ClientConnectionManager conMgr = new ThreadSafeClientConnManager(params, schReg);

            return new DefaultHttpClient(conMgr, params);

        } catch (Exception e) {
            return new DefaultHttpClient();
        }
    }
_

しかし、これにより_Connection closed by peer_エラーが発生します。

私は何を間違えていますか?自己署名証明書を使用した内部ネットワークであるため、証明書を安全に無視できますが、vertを制御できず、アプリのユーザーが異なる証明書を持っている可能性があるため、実際に証明書を受け入れるかバイパスする必要があります。

ありがとう

編集------------------------------

以下のMy-Name-Isの回答を試した後、提案されたとおりにCustomX509TrustManagerクラスを作成し、次にそれを使用してカスタムHttpClientを作成します。

_private HttpClient sslClient(HttpClient client) {
        try {
            CustomX509TrustManager tm = new CustomX509TrustManager();
            SSLContext ctx = SSLContext.getInstance("TLS");
            ctx.init(null, new TrustManager[] { tm }, null);
            SSLSocketFactory ssf = new MySSLSocketFactory(ctx);
            ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            ClientConnectionManager ccm = client.getConnectionManager();
            SchemeRegistry sr = ccm.getSchemeRegistry();
            sr.register(new Scheme("https", ssf, 8080));
            return new DefaultHttpClient(ccm, client.getParams());
        } catch (Exception ex) {
            return null;
        }
    }
_

最後に、このHttpClientを次のように使用します。

_private class httpGETTask extends AsyncTask<GetParams, Void, String> {
private Exception e = null;

@Override
protected String doInBackground(GetParams... params) {
    // Set connection parameters
    HttpParams httpParameters = new BasicHttpParams();
    int timeoutConnection = 15000;
    HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
    int timeoutSocket = 15000;
    HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

    Log.v(TAG, params[0].path);
    HttpClient httpclient = new DefaultHttpClient(httpParameters);
    httpclient = sslClient(httpclient);

    HttpResponse response;
    String responseString = null;
    try {
        // Try connection
        HttpGet get = new HttpGet(params[0].path);
        get.addHeader("Authorization",
                "Basic "
                        + Base64.encodeBytes(new String(params[0].username + ":" + params[0].password)
                                .getBytes()));

        response = httpclient.execute(get);
        StatusLine statusLine = response.getStatusLine();
        if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            response.getEntity().writeTo(out);
            out.close();
            responseString = out.toString();
        } else {
            // Closes the connection.
            response.getEntity().getContent().close();
            throw new IOException(statusLine.getReasonPhrase());
        }
    } catch (ClientProtocolException e) {
        Log.e(TAG, "ClientProtocolException");
        this.e = e;
    } catch (IOException e) {
        Log.e(TAG, "IOException");
        this.e = e;
    }
    return responseString;
_

ログに記録されるパスの形式は_https://ipaddress:8080/Page.html_ですが、_Connection closed By Peer_エラーが表示されます。

05-24 08:20:32.500:E/ConnectionHelper(1129):IOException 05-24 08:20:32.550:E/ConnectionHelper(1129):コンテンツの読み込み例外05-24 08:20:32.550:E/ConnectionHelper(1129 ):javax.net.ssl.SSLException:接続がピア05-24 08:20:32.550によって閉じられました:E/ConnectionHelper(1129):at org.Apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake(Native Method) 05-24 08:20:32.550:E/ConnectionHelper(1129):org.Apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.Java:410)05-24 08:20:32.550:E/ConnectionHelper(1129):at org.Apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl $ SSLInputStream。(OpenSSLSocketImpl.Java:643)05-24 08:20:32.550:E/ConnectionHelper(1129):at org.Apache。 harmony.xnet.provider.jsse.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.Java:614)05-24 08:20:32.550:E/ConnectionHelper(1129):at org.Apache.http.impl.io.SocketInputBuffer。(SocketInputBuffer。 Java:70)05-24 08:20:32.550:E/ConnectionHelper(1129):at org.Apache.http.impl.Soc ketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.Java:83)05-24 08:20:32.550:E/ConnectionHelper(1129):at org.Apache.http.impl.conn.DefaultClientConnection.createSessionInputBuffer(DefaultClientConnection.Java:170)05-24 08:20:32.550:E/ConnectionHelper(1129):org.Apache.http.impl.SocketHttpClientConnection.bind(SocketHttpClientConnection.Java:106)05-24 08:20:32.550:E/ConnectionHelper(1129):at org .Apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.Java:129)05-24 08:20:32.550:E/ConnectionHelper(1129):at org.Apache.http.impl.conn.DefaultClientConnectionOperator.openConnection( DefaultClientConnectionOperator.Java:172)05-24 08:20:32.550:E/ConnectionHelper(1129):at org.Apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.Java:164)05-24 08:20: 32.550:E/ConnectionHelper(1129):org.Apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.Java:119)05-24 08:20:32.550:E/ConnectionHelper( 1129):org.Apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.Java:360)05-24 08:20:32.550:E/ConnectionHelper(1129):org.Apache.http.impl.client .AbstractHttpClient.execute(AbstractHttpClient.Java:555)05-24 08:20:32.550:E/ConnectionHelper(1129):at org.Apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.Java:487)05- 24 08:20:32.550:E/ConnectionHelper(1129):org.Apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.Java:465)05-24 08:20:32.550:E/ConnectionHelper(1129) :com.d_apps.my_app.connection_helpers.ConnectionHelper $ httpGETTask.doInBackground(ConnectionHelper.Java:114)で

28
Darren

次のソースが問題を解決するはずです。

import Android.app.Activity;
import Android.widget.EditText;
import Android.os.Bundle;
import org.Apache.http.HttpResponse;
import org.Apache.http.Header
import Java.io.InputStream;
import Java.io.BufferedReader;
import Java.io.InputStreamReader;
import Android.util.Log;
import Android.view.Menu;
public class MainActivity extends Activity {

    private EditText text;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text = (EditText) findViewById(R.id.editText1);
        connect();
    }

    private void connect(){
        try {
            DataLoader dl = new DataLoader();
            String url = "https://IpAddress";
            HttpResponse response = dl.secureLoadData(url); 

            StringBuilder sb = new StringBuilder();
            sb.append("HEADERS:\n\n");

            Header[] headers = response.getAllHeaders();
            for (int i = 0; i < headers.length; i++) {
                Header h = headers[i];
                sb.append(h.getName()).append(":\t").append(h.getValue()).append("\n");
            }

            InputStream is = response.getEntity().getContent();
            StringBuilder out = new StringBuilder();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            for (String line = br.readLine(); line != null; line = br.readLine())
                out.append(line);
            br.close();

            sb.append("\n\nCONTENT:\n\n").append(out.toString()); 

            Log.i("response", sb.toString());
            text.setText(sb.toString());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

}


import Android.app.Application;
import Android.content.Context;
import Java.io.InputStream;
public class MeaApplication extends Application {

    private static Context context;

    @Override
    public void onCreate() {
        super.onCreate();
        MeaApplication.context = getApplicationContext();
    }

    public static Context getAppContext() {
        return MeaApplication.context;
    }

    public static InputStream loadCertAsInputStream() {
        return MeaApplication.context.getResources().openRawResource(
                R.raw.meacert);
    }

}


import org.Apache.http.conn.ssl.SSLSocketFactory;
import javax.net.ssl.SSLContext;
import Java.security.KeyStore;
import Java.security.NoSuchAlgorithmException;
import Java.security.KeyManagementException;
import Java.security.KeyStoreException;
import Java.security.UnrecoverableKeyException;
import javax.net.ssl.TrustManager;
import Java.net.Socket;
import Java.io.IOException;
import Java.net.UnknownHostException;
/**
 * Taken from: http://janis.peisenieks.lv/en/76/english-making-an-ssl-connection-via-Android/
 *
 */
public class CustomSSLSocketFactory extends SSLSocketFactory {
    SSLContext sslContext = SSLContext.getInstance("TLS");

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

        TrustManager tm = new CustomX509TrustManager();

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

    public CustomSSLSocketFactory(SSLContext context)
            throws KeyManagementException, NoSuchAlgorithmException,
            KeyStoreException, UnrecoverableKeyException {
        super(null);
        sslContext = context;
    }

    @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();
    }
}


import javax.net.ssl.X509TrustManager;
import Java.security.cert.CertificateException;
import Java.security.cert.X509Certificate;
import Java.io.IOException;
import Java.io.InputStream;
import Java.security.cert.CertificateFactory;
public class CustomX509TrustManager implements X509TrustManager {

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

    @Override
    public void checkServerTrusted(Java.security.cert.X509Certificate[] certs,
            String authType) throws CertificateException {

        // Here you can verify the servers certificate. (e.g. against one which is stored on mobile device)

        // InputStream inStream = null;
        // try {
        // inStream = MeaApplication.loadCertAsInputStream();
        // CertificateFactory cf = CertificateFactory.getInstance("X.509");
        // X509Certificate ca = (X509Certificate)
        // cf.generateCertificate(inStream);
        // inStream.close();
        //
        // for (X509Certificate cert : certs) {
        // // Verifing by public key
        // cert.verify(ca.getPublicKey());
        // }
        // } catch (Exception e) {
        // throw new IllegalArgumentException("Untrusted Certificate!");
        // } finally {
        // try {
        // inStream.close();
        // } catch (IOException e) {
        // e.printStackTrace();
        // }
        // }
    }

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

}


import org.Apache.http.HttpResponse;
import org.Apache.http.client.ClientProtocolException;
import Java.io.IOException;
import Java.security.NoSuchAlgorithmException;
import Java.security.KeyManagementException;
import Java.net.URISyntaxException;
import Java.security.KeyStoreException;
import Java.security.UnrecoverableKeyException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import Java.security.SecureRandom;
import org.Apache.http.client.HttpClient;
import org.Apache.http.impl.client.DefaultHttpClient;
import org.Apache.http.conn.ssl.SSLSocketFactory;
import org.Apache.http.conn.ClientConnectionManager;
import org.Apache.http.conn.scheme.Scheme;
import org.Apache.http.conn.scheme.SchemeRegistry;
import org.Apache.http.client.methods.HttpGet;
public class DataLoader {

    public HttpResponse secureLoadData(String url)
            throws ClientProtocolException, IOException,
            NoSuchAlgorithmException, KeyManagementException,
            URISyntaxException, KeyStoreException, UnrecoverableKeyException {
        SSLContext ctx = SSLContext.getInstance("TLS");
        ctx.init(null, new TrustManager[] { new CustomX509TrustManager() },
                new SecureRandom());

        HttpClient client = new DefaultHttpClient();

        SSLSocketFactory ssf = new CustomSSLSocketFactory(ctx);
        ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        ClientConnectionManager ccm = client.getConnectionManager();
        SchemeRegistry sr = ccm.getSchemeRegistry();
        sr.register(new Scheme("https", ssf, 443));
        DefaultHttpClient sslClient = new DefaultHttpClient(ccm,
                client.getParams());

        HttpGet get = new HttpGet(new URI(url));
        HttpResponse response = sslClient.execute(get);

        return response;
    }

}
56
My-Name-Is

「信頼されていない」(開発者)証明書を使用している場合、以下が解決策です。すべての証明書を信頼する必要がありますが、その方法は次のとおりです。信頼できる証明書の場合、以下の機能を追加せずに機能します。httpをhttpsに変更するだけで機能します。

信頼できない証明書の解決策を次に示します。

HttpClientの方法では、org.Apache.http.conn.ssl.SSLSocketFactory自体ではなく、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;

import org.Apache.http.conn.ssl.SSLSocketFactory;
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();
    }
}

httpClientのインスタンスの作成中にこのクラスを使用します。

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();
    }
}
14
santhosh

デバイスの日付を確認してください。別の年に変更した可能性があります。子供が私の電話を使用するとき、私は常にこの問題を経験します。

7
Kris Yu

AndroidはSSL検証に関してiOSおよびデスクトップブラウザよりも制限されているため、信頼できる証明書を使用してサーバーにアクセスできる場合は、SSLを正しく構成することをお勧めします。

このソリューションは、Androidアプリでの変更を必要としないため、よりクリーンです。

ApacheのSSL構成の例を次に示します(VirtualHost定義に追加します(例:/ etc/Apache2/sites-enabled))

SSLEngine on
SSLCertificateFile    YOUR_CERT_PATH
SSLCACertificateFile  CA_ROOT_CERT_PATH
SSLCertificateKeyFile KEY_PATH

私は同じエラーがあり、CAルート証明書を追加したときにエラーがなくなり、Androidはもう文句を言いませんでした。これらのファイルの正しいパスを提供し、Apacheを再起動して再度テストします。

CAルート証明書のファイルには、ルート証明書と中間証明書の両方を含めることができます

このサイト を使用してSSL構成をテストし、の結果で、サーバーがすべてを送信していることを確認できます必要な証明書。

3
iTech

この例外を検索する場合、「すべての証明書を許可する」を実装するようアドバイスするだけです。

SSLPeerUnverifiedExceptionのjavadocの状態:

ピアが自分自身を識別できなかった場合(たとえば、証明書がない、使用されている特定の暗号スイートが認証をサポートしていない、またはSSLハンドシェイク中にピア認証が確立されなかった)、この例外がスローされます。

そのため、エラーは接続が不安定で不安定であり、リクエストにとてつもない時間がかかる可能性があります。モバイルアプリでは、これらのSSLPeerUnverifiedExceptionと組み合わせて、多くの接続/ソケットタイムアウトが発生することがあります。一部の要求は通過しますが、60秒以上かかります。これらの場合、ネットワーク接続はあらゆる手段を超えて単純に吸い込まれます。

このような場合、単に「すべての証明書を許可する」を強引に強制することはお勧めできません-適切な再試行戦略を実装してください。

1
icyerasor

アプリの起動時にAndroidのセキュリティプロバイダーの更新を許可します。

5.0+より前のデフォルトのプロバイダーはSSLv3を無効にしません。 Google Play開発者サービスにアクセスできれば、アプリからAndroidのセキュリティプロバイダーにパッチを適用するのは比較的簡単です。

  private void updateAndroidSecurityProvider(Activity callingActivity) {
    try {
        ProviderInstaller.installIfNeeded(this);
    } catch (GooglePlayServicesRepairableException e) {
      // Thrown when Google Play Services is not installed, up-to-date, or  enabled
        // Show dialog to allow users to install, update, or otherwise    enable Google Play services.
       GooglePlayServicesUtil.getErrorDialog(e.getConnectionStatusCode(), callingActivity, 0);
    } catch (GooglePlayServicesNotAvailableException e) {
        Log.e("SecurityException", "Google Play Services not available.");
    }
}

ソース: ProviderInstallerプロバイダーでセキュリティプロバイダーにパッチを適用

1
nani