«

»

Oct 03

Java – как доверять всем ssl сертификатам

Оставим за пределами данной заметки рассуждения касательно безнравственности поставленной задачи и перейдем непосредственно к рассмотрению возможных способов ее решения на java (для android-приложений также вполне актуально).

1 cпособ – Как доверять всем ssl-сертификатам, используя HttpsURLConnection:

Создадим класс описывающий интерфейс для управления сертификатами безопасности стандарта X509 (вот тут описано в деталях что это такое):

private class X509_Trust_Manager implements X509TrustManager
{
    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType)
    throws CertificateException {}
    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
    throws CertificateException {}
    @Override
    public X509Certificate[] getAcceptedIssuers()
    {
        return null;
    }
};

Создадим экземпляр класса для проверки (а вернее ее отсутствии) для любых соединений:

HostnameVerifier TRUST_ALL_CERTIFICATES = new HostnameVerifier()
{
    public boolean verify(String hostname, SSLSession session)
    {
        return true;
    }
};

Используя их, инициализируем объект, определяющий будущее защищенное соединение. Этот объект предоставляет нам фабрику по созданию защищенных сокетов.

SSLContext Cur_SSL_Context = null;
try
{
    Cur_SSL_Context = SSLContext.getInstance("TLS");
    Cur_SSL_Context.init(null, new TrustManager[] { new X509_Trust_Manager() }, new SecureRandom());
}
catch (Exception e)
{
    e.printStackTrace();
}

И, наконец, указываем, что для всех https-соединений нашего приложения, по умолчанию, мы хотим доверять всем сертификатам:

HttpsURLConnection.setDefaultHostnameVerifier(TRUST_ALL_CERTIFICATES);
HttpsURLConnection.setDefaultSSLSocketFactory(Cur_SSL_Context.getSocketFactory());

2 способ – Как доверять всем ssl-сертификатам, используя HttpClient

Для начала, нам необходимо расширить стандартную фабрику – SSLSocketFactory, так, чтобы она использовала наш менеджер для управления доверенными соединениями (X509_Trust_Manager).

Перво-наперво: есть две имплементации класса SSLSocketFactory:  javax.net.ssl.SSLSocketFactory и org.apache.http.conn.ssl.SSLSocketFactory. Использовать надо именно апачевскую (org.apache.http.conn.ssl.SSLSocketFactory). И да, это критично.

В примере ниже используется класс X509_Trust_Manager, определенный в примере для HttpsURLConnection, описывающий интерфейс для управления сертификатами безопасности стандарта X509.

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

После чего задаем параметры нашего будущего соединения, указывая, что для построения защищенного канала необходимо использовать нашу, определенную выше, фабрику SSLSocketFactory. При проверке сертификатов безопасности она вызывает методы единственного доступного менеджера для управления сертификатами (X509_Trust_Manager), который одобряет все сертификаты не глядя. На основе этих параметров мы получаем HttpClient, который можно использовать для организации обмена данными между клентом и сервером по защищенному соединению.

HttpClient client = null;
try
{
    SchemeRegistry Current_Scheme = new SchemeRegistry();
    Current_Scheme.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
    Current_Scheme.register(new Scheme("https", new Naive_SSLSocketFactory(), 443));
    HttpParams Current_Params = new BasicHttpParams();
    ThreadSafeClientConnManager Current_Manager = new ThreadSafeClientConnManager(Current_Params,Current_Scheme);
    client = new DefaultHttpClient(Current_Manager, Current_Params);
}
catch(Exception e)
{
    e.printStackTrace();
}

Преимущество варианта с HttpClient в возможности реализовать действительно многопоточное взаимодействие клиента с сервером на основе MultiThreadedHttpConnectionManager (о чем можно почитать тут и тут), тогда как при использовании HttpsURLConnection передача данных осуществляется по принципу “пока не получил ответа на предыдущий запрос – больше ничего спрашивать и не стану”. Да, данные снипеты вполне могут использоваться и под android.

Ссылки по теме “Работа с ssl-сертификатами и httpClient в java“:

http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html
http://stackoverflow.com/questions/2642777/trusting-all-certificates-using-httpclient-over-https
http://blog.crazybob.org/2010/02/android-trusting-ssl-certificates.html
http://stackoverflow.com/questions/995514/https-connection-android#1000205
http://homepage.mac.com/kelleherk/iblog/C149402102/E773353034/index.html

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>