Всегда ли самозаверяющие сертификаты подвержены атаке «человек посередине» при программном добавлении сертификата?

Я создаю клиентское приложение jax-ws, которое должно принимать самозаверяющие сертификаты. Но есть и распространенная проблема исключения SSL-рукопожатия, когда вы пытаются импортировать самозаверяющие сертификаты. Таким образом, наиболее распространенным решением для этого является расширение поставщика безопасности JSSE и инициализация контекста SSL для принятия всех сертификатов, таких как:

Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
TrustManager[] trustCerts = new TrustManager[]{new X509TrustManager() {
                        public X509Certificate[] getAcceptedIssuers() {
                            return null;
                        }

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

                        public void checkClientTrusted(X509Certificate[]
                        certs, String authType) throws CertificateException {
                            return;
                        }
                    }
            }; 
SSLContext sc = SSLContext.getInstance("SSLv3");
sc.init(null, trustCerts, null);
SocketFactory factory = sc.getSocketFactory();
SSLSocket socket;
socket = (SSLSocket) factory.createSocket(mInstance.getHostName(),getSecureConnectionEndpoint().getPort());
socket.startHandshake();
setCerts(socket.getSession().getPeerCertificates());

Это был единственный обходной путь, который я смог найти для решения проблемы. Здесь есть много подобных вопросов, таких как Импорт SSL-сертификатов, и все они предлагают одно и то же решение.

Это, очевидно, очень подвержено атаке «человек посередине», и это решение кажется законным только для целей тестирования.

Итак, мой вопрос: нет ли способа сделать весь этот процесс более безопасным, когда вы пытаетесь программно импортировать сертификаты?

Заранее спасибо!


person agenthost    schedule 30.07.2015    source источник
comment
Это не попытка ответить на ваш вопрос, но: не используйте SSLv3, так как он ошибочен, Google и т. д. рекомендуют TLS1.0 как абсолютный минимум.   -  person Rodney    schedule 30.07.2015
comment
Спасибо! Я запомню это :)   -  person agenthost    schedule 30.07.2015


Ответы (3)


Это, очевидно, очень подвержено атаке «человек посередине», и это решение кажется законным только для целей тестирования.

Правильный. Это радикально небезопасно.

Итак, мой вопрос: нет ли способа сделать весь этот процесс более безопасным, когда вы пытаетесь программно импортировать сертификаты?

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

NB. Размещенный вами код не соответствует условиям контракта getAcceptedIssuers().. Он не может возвращать значение null.

person user207421    schedule 30.07.2015
comment
Спасибо за Ваш ответ! Но getAcceptedIssuers() должен возвращать значение null, чтобы клиент мог получить самозаверяющие сертификаты сервера. - person agenthost; 30.07.2015
comment
Это неверно, и в Javadoc прямо говорится об обратном. Вы это читали? - person user207421; 31.07.2015

Возможно, вместо того, чтобы использовать самоподписанные сертификаты, вам лучше создать центр сертификации и доверять ему?

Я использую XCA для запуска собственного частного центра сертификации и выпуска сертификатов — он очень прост в использовании и понимании.

Чтобы заставить Java доверять вашему ЦС, вам нужно импортировать корневой сертификат — создайте хранилище доверенных сертификатов с помощью keytool.

keytool -importcert -file myca.crt -keystore mykeystore.jks

Затем импортируйте хранилище доверенных сертификатов, используя следующий аргумент JVM.

-Djavax.net.ssl.trustStore=/home/user/mykeystore.jks
person Rodney    schedule 30.07.2015
comment
Да, это самый простой способ сделать это. Но ландшафт на стороне сервера может иметь несколько серверов, и было бы обременительно создавать корневой сертификат для каждого сервера. - person agenthost; 30.07.2015

Шифрование работает одинаково независимо от того, является ли оно самоподписанным или подписанным CA. Единственная разница заключается в том, что если вы подписываете себя самостоятельно, будет отображаться предупреждение о том, что вы являетесь владельцем нашего сайта, и полученный сервер может расшифровать вашу личную информацию и использовать ее в злонамеренных целях. Для самоподписания вы не можете проверить, что сервер является тем, кем он себя называет. Данные зашифрованы независимо от того, подписаны они сами или подписаны CA, и для атаки «человек посередине» я не вижу разницы. Возможно, кто-то перехватывает пакеты с помощью wireshark или nmap и т. д., но в обоих сценариях одинаково независимо от того, подписаны они сами или подписаны CA. Обычно для разработки и тестирования используются самозаверяющие сертификаты, а в prod используются подписанные сертификаты ЦС. Вы не хотите, чтобы конечные пользователи шли на риск, связанный с сайтом, чтобы сэкономить несколько долларов.

  If you are consuming the service in Java code you need to import the self 
 signed certificate in cacerts present in <PATH_TO_JRE>\lib\security\cacerts by
 the following command >keytool -import -alias <Alias Name> -file "PATH_TO_.crt"
 -keystore "PATH_TO_cacerts" -ext san=ip:127.0.0.1 

Вы также можете использовать доменное имя, например www.mydomain.com, в san вместо ip.

person Goyal Vicky    schedule 30.08.2015