Ошибка SSL SSL HttpGet (без сертификата партнера) ИЛИ (соединение закрыто одноранговым)

Я пытаюсь сделать простой HttpGet для чтения веб-страницы. Я работаю над iOS и работаю над Android через http, но не https.

URL-адрес - это внутренний IP-адрес и настраиваемый порт, поэтому я могу читать с помощью http, как это, используя путь http://ipaddress:port/MyPage.html

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): при org.apache.harmony.xnet.provider.jsse.NativeCrypto.SSL_do_handshake (Native Метод) 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): при org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl $SSLInputStream. (OpenSSLSocketImpl.java:643) 05-24 08: 20: 32.550: E/ConnectionHelper (1129): при org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:614) 05-24 08: 20: 32.550: E/ConnectionHelper (1129): при org.apache.http.impl.io.SocketInputBuffer. (SocketInputBuffer.java:70) 05-24 08: 20: 32.550: E/ConnectionHelper (1129): при org.apache.http.impl.SocketHttpClientConnection.createSessionInputBuffer(SocketHttpClientConnection.java:83) 05-24 08: 20: 32.550: E/ConnectionHelper (1129): при 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): при org.apache.http.impl.conn.DefaultClientConnection.openCompleted(DefaultClientConnection.java:129) 05-24 08: 20: 32.550: E/ConnectionHelper (1129): при org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:172) 05-24 08: 20: 32.550: E/ConnectionHelper (1129): при 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): при 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)

Ответ 1

Следующий источник должен исправить вашу проблему.

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;
    }

}

Ответ 2

Если вы используете сертификат "Не доверяемый" (разработчик), ниже это решение. Нам нужно доверять всем сертификатам, и ниже это способ сделать это. Для доверенных сертификатов он работает без добавления ниже функциональности, мы просто должны изменить 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();
    }
}

Ответ 3

Проверьте дату своего устройства. Возможно, вы изменили его на другой год. Я постоянно получаю эту проблему, когда дети используют мой телефон.

Ответ 4

Если у вас есть доступ к серверу с доверенным сертификатом, гораздо лучшее решение для правильной настройки SSL, потому что андроид более ограничен, что iOS и настольный браузер в отношении проверки SSL

Это решение не требует каких-либо изменений в вашем приложении для Android, поэтому оно более чистое.

Вот пример конфигурации SSL для apache (добавьте его в определение VirtualHost, например, /etc/apache 2/sites)

SSLEngine on
SSLCertificateFile    YOUR_CERT_PATH
SSLCACertificateFile  CA_ROOT_CERT_PATH
SSLCertificateKeyFile KEY_PATH

У меня была такая же ошибка, и когда я добавил корневой сертификат CA, ошибка исчезла, и андроид больше не жаловался. Укажите правильные пути для этих файлов, перезапустите Apache и снова проверьте.

Файл для корневого сертификата CA может содержать как корневой, так и промежуточный сертификат

Вы можете проверить свою конфигурацию SSL с помощью этого сайта и убедиться, что в результате в разделе "Пути сертификации" сервер отправляет все необходимые сертификаты.

Ответ 5

При поиске этого исключения все, что вы получаете, это рекомендация по внедрению "разрешить все сертификаты".

В javadoc для SSLPeerUnverifiedException указано:

Когда одноранговый узел не смог идентифицировать себя (например, никакой сертификат, используемый конкретный шифровой набор не поддерживает аутентификацию, или при авторизации SSL не было установлено равноправное подтверждение подлинности), это исключение вызывается.

Таким образом, ошибка может заключаться в том, что соединение настолько неустойчиво/неустойчиво, и запросы занимают нелепое количество времени. В нашем мобильном приложении мы иногда испытываем много соединений /Socket -Timeouts в сочетании с этим SSLPeerUnverifiedException. Некоторые запросы проходят, но принимают 60 с + - сетевое соединение просто всасывает все средства в этих случаях.

Просто грубое принуждение к этому с помощью "разрешить все сертификаты" не рекомендуется в таких случаях - скорее реализуйте правильную стратегию повтора.

Ответ 6

Разрешить поставщику безопасности 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

Ответ 7

Я изначально использовал HttpsURLConnection, но он не работал последовательно, поэтому я решил пойти с HttpClient. Теперь он работает.