menu

Использование HTTPS в клиентских приложениях
( Мэтт Тауэрс )

Как использовать HTTPS протокол вместе со стандартным классом URL.

Tips 'N Tricks
 

Если вы когда-либо пробовали устанавливать защищенное соединение между клиентом Java и HTTPS (Hypertext Transfer Protocol Secure) сервером, то вы вероятно обнаружили что стандартный класс java.net.URL не поддерживает протокол HTTPS. Серверная часть этой задачи довольно очевидная. Почти любой Web-сервер, доступный сегодня, предусматривает механизм для обмена данными, используя протокол HTTPS. Как только вы установили ваш Web-сервер, любой браузер может запрашивать информацию по протоколу HTTPS от вашего сервера просто определяя HTTPS как протокол для URL. Если у вас еще не установлен HTTPS сервер, вы можете проверять ваш клиентский код почти с любыми HTTPS страницами в Internet. Раздел Ресурсы содержит короткий список возможных страниц, которые вы можете использовать для этой цели.

С точки зрения клиента, простота 'S' в конце знакомого HTTP обманчива. Браузер фактически делает значительное количество 'теневой' работы, чтобы гарантировать, что никто не вмешался в процесс передачи или контролировал информацию, которую вы запросили. Как известно, алгоритм кодирования для HTTPS патентован RSA Security (в течение, по крайней мере, еще нескольких месяцев). Использование этого алгоритма было лицензировано изготовителями браузера, но не было лицензировано Sun Microsystems для того, чтобы включить его в стандартную реализацию класса Java URL. В результате, если вы пытаетесь создавать объект URL со строкой, определяющей HTTPS как протокол, будет сгенерировано MalformedURLException.

К счастью, чтобы преодолеть это ограничение, спецификация Java предусматривает способность выбрать дополнительный обработчик потока (stream handler) для класса URL. Однако методика, требуемая для его реализации различна в зависимости от используемой JVM. Для Microsoft JDK1.1 — совместимой JVM, JView, Microsoft лицензировала алгоритм и реализовала HTTPS как часть пакета wininet. Sun, с другой стороны, недавно выпустила Java Secure Sockets Extension (JSSE) для JDK1.2-совместимой JVM, в котором Sun также лицензировала и реализовала обработчик потока HTTPS. Эта статья демонстрирует, как реализовать использование обработчика потока с поддержкой HTTPS, используя JSSE и пакет wininet Microsoft.

JDK 1.2-совместимая JVM

Метод, использующий JDK1.2-совместимую JVM прежде всего предполагает использование Java Secure Sockets Extension (JSSE) 1.0.1. Прежде чем такой подход заработает, вы должны установить JSSE и добавить соответствующий путь при компиляции рассматриваемого клиентского приложения.

После того, как вы установили JSSE, вы должны установить свойства системы и добавить новый security provider к объекту класса Security. Есть различные способы сделать обе вышеуказанные вещи, но для целей данной статьи более всего подходит следующий метод:

System.setProperty("java.protocol.handler.pkgs",
 "com.sun.net.ssl.internal.www.protocol");
 Security.addProvider
 (new com.sun.net.ssl.internal.ssl.Provider());

После вызова двух предыдущих методов, MalformedURLException в нижеследующем коде не должно выбрасываться:

URL url = new URL("https://[your server]");

Если вы устанавливаете соединение по SSL на стандартный, 443 порт, добавлять номер порта к строке URL не обязательно. Однако, если ваш Web-сервер использует нестандартный порт для SSL соединения, добавление номера порта к строке URL необходимо:

URL url = new URL("https://[your server]:7002");

Недостаток этой методики касается URL и относится к серверу, который имеет неподписанный или недопустимый SSL сертификат. В этом случае попытка получить входной или выходной поток от URLConnection объекта приведет к SSLException с сообщением "untrusted server cert chain". Если сервер имеет правильный и подписанный сертификат, то никакое исключение не выбросится.

URL url = new URL("https://[your server]");
 URLConnection con = URL.openConnection();
 //здесь может возникнуть SSLException
 //если сертификат сервера неверный
 con.getInputStream();

Очевидное решение этой проблемы — подписанные сертификаты для вашего сервера. Однако, рассмотрение этого вопроса было предложено и результаты можно найти на форуме Java Developer Connection : http:// forum.java.sun.com/forum?14@@.787ad8de.

Microsoft JView

Частично благодаря продолжающемуся спору между Microsoft и Sun по лицензированию Java для использования на платформах Windows, Microsoft JView JVM в настоящее время только JDK 1.1-совместима. Поэтому методика, описанная выше не будет работать для клиентов, выполняющихся в JView, поскольку JSSE требует по крайней мере 1.2.2-совместимой JVM. Достаточно удобно то, что Microsoft предлагает обработчик потока ('stream handler') HTTPS как часть пакетаcom.ms.net.wininet.

Вы можете установить обработчик потока в среде JView посредством вызова единственного статического метода класса URL:

URL.setURLStreamHandlerFactory(new
 com.ms.net.wininet.WininetStreamHandlerFactory());

После вызова вышеуказанного метода, MalformedURLException из следующего кода не должно выбрасываться:

URL url = new URL("https://[your server]");

Есть два недостатка, связанные с этой методикой. Во первых, согласно документации по JDK, метод setURLStreamHandlerFactory может быть вызван только однажды в данной JVM. Последующие попытки вызвать этот метод приведут к ошибке. Во вторых, как и в случае решения с JVM 1.2, вы должны быть осторожны при использовании URL, который обращается к серверу с неподписанным или недопустимым SSL сертификатом. Как и в предыдущем случае, проблема возникает когда делается попытка получить входной или выходной поток из объекта URLConnection. Однако, вместо SSLException, обработчик потока Microsoft выбрасывает стандартное IOException.

URL url = new URL("https://[your server]");
 URLConnection con = url.openConnection();
 //здесь может возникнуть IOException
 //если сертификат сервера неверный
 con.getInputStream();

Опять, очевидное решение этой проблемы — попытка установления HTTPS соединения только с серверами, имеющими подписанные, верные сертификаты. Однако, JView предлагает еще одну возможность. Непосредственно перед получением входного или выходного потока от объекта URLConnection, вы можете вызвать setAllowUserInteraction(true) этого объекта. Это заставит JView дать сообщение, предупреждающее пользователя, что сертификаты сервера недопустимы, но предоставить пользователю возможность продолжения. Имейте в виду, однако, что подобные сообщения могут быть разумны для desktop приложения, но появление диалогового окна при соединении с вашим сервером для любых целей кроме отладочных, неприемлемо.

Внимание: Вы можете также вызывать метод setAllowUserInteraction() и в JDK 1.2-совместимой JVM. Однако при использовании Sun 1.2 JVM (с которой этот код был протестирован), никакие диалоги не возникают, даже когда это свойство установлено в true.

URL url = new URL("https://[your server]");
 URLConnection con = url.openConnection();
 //заставляет JVM отобразить диалог
 //о соединении с "недоверяемым" сервером
 con.setAllowUserInteraction(true);
 con.getInputStream();

Пакет com.ms.net.wininet должен быть установлен и помещен в переменную окружения CLASSPATH по умолчанию в системах Windows NT 4.0, Windows 2000 и Windows 9x. Также, в соответствии с документацией по Microsoft JDK, WinInetStreamHandlerFactory это "... обработчик, который установлен по умолчанию при запуске апплетов".

Платформенная независимость

Хотя оба из вышеописанных методов покрывают большинство платформ, на которых ваш Java-клиент может работать, ваш Java-клиент, должен работать как на JDK1.1- так и JDK1.2- совместимой JVM. "Write once, run anywhere", помните? Как оказывается, комбинировать эти два метода так, чтобы соответствующий обработчик был загружен в зависимости от JVM, довольно целесообразно. Следующий код демонстрирует один из способов:

String strVendor =
System.getProperty("java.vendor");
 String strVersion = System.getProperty("java.version");
 //получаем версию системы как string формы:
 //[major].[minor].[release] (например 1.2.2)
 Double dVersion = new Double(strVersion.substring(0, 3));

 //если используется JVM Microsoft,
 //используем обработчик потока от Microsoft
 if( -1 < strVendor.indexOf("Microsoft") )
 { try
 {
 Class clsFactory =
 Class.forName
 ("com.ms.net.wininet.WininetStreamHandlerFactory");
 if ( null != clsFactory )
 URL.setURLStreamHandlerFactory(
 (URLStreamHandlerFactory)clsFactory.newInstance());
 }
 catch( ClassNotFoundException cfe )
 {
 throw new Exception("Unable to load the
Microsoft SSL " +
 "stream handler. Check
classpath." + cfe.toString());
 }
 //если обработчик потока был
 //удачно установлен, устанавливаем
 //соответствующий флаг
 //и "подавляем" ошибку
 catch( Error err ){m_bStreamHandlerSet = true;}
 }
 //если используется "нормальная"
JRE,
 //пытаемся использовать JSSE handler.
 //NOTE: JSSE требует 1.2 или выше
 else if( 1.2 <= dVersion.doubleValue() )
 {
 System.setProperty("java.protocol.handler.pkgs",
 "com.sun.net.ssl.internal.www.protocol");
 try
 {
 //если JSSE provider доступен и он еще
 //не установлен,
 //добавляем его как нового
 //провайдера в класс Security
 Class clsFactory =
Class.forName
 ("com.sun.net.ssl.internal.ssl.Provider");
 if( (null != clsFactory) && (null ==
 Security.getProvider("SunJSSE")) )
 Security.addProvider
 ((Provider)clsFactory.newInstance());
 }
 catch( ClassNotFoundException cfe )
 {
 throw new Exception("Unable to load the
 JSSE SSL stream handler." +
 "Check classpath." +
 cfe.toString());
 }
 }

Работа с апплетами

Выполнение HTTPS-соединения из апплета кажется естественным расширением указанных выше сценариев. В реальности это даже легче. В версиях 4.0 (или более поздних) Netscape Navigator и Internet Explorer, HTTPS доступен по-умолчанию для соответствующих JVM. Следовательно, если вы хотите создать HTTPS-соединение из вашего апплета, просто укажите HTTPS как протокол при создании экземпляра класса URL:

URL url = new URL("https://[your server]");

Если браузер-клиент использует Sun Java 2 plug-in, на использование HTTPS накладываются дополнительные ограничения. Полная информация по использовании HTTPS с Java 2 plug-in может быть найдена на web-сайте Sun (java.sun.com)

Заключение

Использование протокола HTTPS между приложениями может быть быстрым и эффективным способом получить разумный уровень защиты для ваших соединений. К сожалению, причины того, что это не поддерживается как часть стандартной спецификации Java, кажутся скорее юридическими нежели техническими. Однако с появлением JSSE и использованием пакета com.ms.net.winint Microsoft, установление защищенного соединения возможно для большинства платформ посредством всего лишь нескольких строк кода.

Об авторе

Matt Towers, или как он себя сам называет, eBozo, недавно оставил позицию разработчика в Visio. С тех пор он работает в начинающей интернет-компании, PredictPoint.com, в Сиэтле, шт. Вашингтон Java-разработчиком.

Ресурсы

Reprinted with permission from JavaWorld magazine. Copyright © ITworld.com, Inc., an IDG Communications company.
View the original article at: http://www.javaworld.com/javaworld/ javatips/jw-javatip96.html



Source: http://www.javaworld.com/javaworld/ javatips/jw-javatip96.html
Category: Java | Added by: tsvetkov (23.01.2009)
Views: 4330 | Rating: 0.0/0