Javaのヒント96:JavaクライアントコードでHTTPSを使用する

JavaクライアントとHTTPS(HyperText Transfer Protocol Secure)サーバー間の安全な通信を実装しようとしたことがある場合は、標準java.net.URLクラスがHTTPSプロトコルをサポートしていないことに気付いたと思います。その方程式のサーバー側の実装はかなり簡単です。現在利用可能なほとんどすべてのWebサーバーは、HTTPSを使用してデータを要求するためのメカニズムを提供します。 Webサーバーをセットアップすると、URLのプロトコルとしてHTTPSを指定するだけで、どのブラウザーでもサーバーに安全な情報を要求できます。 HTTPSサーバーをまだ設定していない場合は、インターネット上のほぼすべてのHTTPSWebページでクライアントコードをテストできます。 「リソース」セクションには、その目的に使用できる候補の短いリストが含まれています。

ただし、クライアントの観点からは、使い慣れたHTTPの最後にあるSの単純さはだまされています。ブラウザは実際には、要求された情報をだれも改ざんまたは監視していないことを確認するために、かなりの量の舞台裏の作業を行っています。実は、HTTPSの暗号化を行うアルゴリズムは、RSA Securityによって特許を取得しています(少なくともあと数か月間)。そのアルゴリズムの使用はブラウザメーカーによってライセンスされていますが、標準のJavaURLクラス実装に含まれるようにSunMicrosystemsによってライセンスされていません。その結果、URLプロトコルとしてHTTPSを指定する文字列を使用してオブジェクトを作成しようとするMalformedURLExceptionと、がスローされます。

幸い、その制約に対応するために、Java仕様では、URLクラスの代替ストリームハンドラーを選択する機能が提供されています。ただし、それを実装するために必要な手法は、使用する仮想マシン(VM)によって異なります。MicrosoftのJDK1.1互換VMであるJViewの場合、Microsoftはアルゴリズムのライセンスを取得し、wininetパッケージの一部としてHTTPSストリームハンドラーを提供しています。一方、Sunは最近、JDK1.2互換VM用のJavaSecure Sockets Extension(JSSE)をリリースしました。この拡張機能では、SunはHTTPSストリームハンドラーのライセンスを取得して提供しています。この記事では、JSSEとMicrosoftのwininetパッケージを使用して、HTTPS対応のストリームハンドラーの使用を実装する方法を示します。

JDK1.2互換の仮想マシン

JDK 1.2互換のVMを使用する手法は、主にJava Secure Sockets Extension(JSSE)1.0.1に依存しています。この手法が機能する前に、JSSEをインストールして、問題のクライアントVMのクラスパスに追加する必要があります。

JSSEをインストールした後、システムプロパティを設定し、Securityクラスオブジェクトに新しいセキュリティプロバイダーを追加する必要があります。これらの両方を行うにはさまざまな方法がありますが、この記事の目的のために、プログラムによる方法を示します。

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

前の2つのメソッド呼び出しを行った後MalformedURLException、次のコードを呼び出しても、はスローされなくなります。

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

標準のSSLポート443に接続している場合は、URL文字列にポート番号を追加するオプションがあります。ただし、WebサーバーがSSLトラフィックに非標準のポートを使用している場合は、次のようにポート番号をURL文字列に追加する必要があります。

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

この手法の注意点の1つは、署名されていない、または無効なSSL証明書を持つサーバーを参照するURLに関するものです。その場合、URLの接続オブジェクトから入力または出力ストリームを取得しようとするSSLExceptionと、「untrusted servercertchain」というメッセージが表示されます。サーバーに有効な署名付き証明書がある場合、例外はスローされません。

URL url = new URL( "// [your server]"); URLConnection con = URL.openConnection(); //サーバー証明書が無効な場合にここでSSLExceptionがスローされますcon.getInputStream();

この問題の明らかな解決策は、サーバーの署名付き証明書を取得することです。ただし、次のURLのいずれかが解決策を提供する場合もあります:「JavaSecure Socket Extension 1.0.2の変更」(SunMicrosystems)またはSunのJava DeveloperConnectionフォーラム。

Microsoft JView

Windowsプラットフォームで使用するためのJavaのライセンスをめぐって、MicrosoftとSunの間で進行中の論争もあり、Microsoft JViewVMは現在JDK1.1にのみ準拠しています。したがって、JSSEには少なくとも1.2.2互換のVMが必要であるため、上記の手法はJViewで実行されているクライアントでは機能しません。ただし、Microsoftは、com.ms.net.wininetパッケージの一部としてHTTPS対応のストリームハンドラーを提供しています。

URLクラスで単一の静的メソッドを呼び出すことにより、JView環境でストリームハンドラーを設定できます。

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

前のメソッド呼び出しを行った後、

MalformedURLException

次のコードを呼び出してもスローされなくなります。

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

その手法に関連する2つの警告があります。まず、JDKのドキュメントによると、setURLStreamHandlerFactoryメソッドは特定のVMで最大1回呼び出される可能性があります。その後、そのメソッドを呼び出そうとすると、がスローされますError。次に、1.2 VMソリューションの場合と同様に、署名されていない、または無効なSSL証明書を持つサーバーを参照するURLを使用する場合は注意が必要です。前の場合と同様に、URLの接続オブジェクトから入力ストリームまたは出力ストリームを取得しようとすると問題が発生します。ただし、SSLExceptionMicrosoftストリームハンドラーは、をスローする代わりに、標準のをスローしますIOException

URL url = new URL( "// [your server]"); URLConnection con = url.openConnection(); //サーバー証明書が無効な場合にここでスローされるIOExceptioncon.getInputStream();

この場合も、この問題の明らかな解決策は、署名された有効な証明書を持つサーバーとのみHTTPS通信を試行することです。ただし、JViewにはもう1つのオプションがあります。 URLの接続オブジェクトから入力ストリームまたは出力ストリームを取得する直前setAllowUserInteraction(true)に、接続オブジェクトを呼び出すことができます。これにより、JViewは、サーバーの証明書が無効であることをユーザーに警告するメッセージを表示しますが、とにかく続行するオプションをユーザーに提供します。ただし、このようなメッセージはデスクトップアプリケーションにとっては妥当な場合がありますが、デバッグ目的以外の目的でサーバーにダイアログボックスを表示することはおそらく受け入れられないことに注意してください。

注:setAllowUserInteraction()JDK1.2互換のVMでメソッドを呼び出すこともできます。ただし、Sunの1.2 VM(このコードがテストされた)を使用する場合、そのプロパティがtrueに設定されていても、ダイアログは表示されません。

URL url = new URL( "// [your server]"); URLConnection con = url.openConnection(); //信頼できないサーバーに接続するときに// VMにダイアログを表示させますcon.setAllowUserInteraction(true); con.getInputStream();

com.ms.net.wininetパッケージがインストールされ、Windows NT 4.0、Windows 2000、およびWindows 9xシステムではデフォルトで、システムのクラスパス上に置かれているように見えます。また、Microsoft JDKのドキュメントによると、WinInetStreamHandlerFactory「...アプレットの実行時にデフォルトでインストールされるのと同じハンドラー」です。

プラットフォームの独立性

私が説明したこれらの手法は両方とも、Javaクライアントが実行される可能性のあるほとんどのプラットフォームをカバーしていますが、JavaクライアントはJDK1.1およびJDK1.2準拠のVMの両方で実行する必要がある場合があります。 「一度書けばどこでも走れる」覚えてる?結局のところ、VMに応じて適切なハンドラーがロードされるように、これら2つの手法を組み合わせるのは、かなり簡単です。次のコードは、そのための1つの方法を示しています。

文字列strVendor = System.getProperty( "java.vendor");文字列strVersion = System.getProperty( "java.version"); //次の形式のシステムバージョン文字列を想定します:// [メジャー]。[マイナー]。[リリース](例:1.2.2)Double dVersion = new Double(strVersion.substring(0、3)); // MS環境で実行している場合は、MSストリームハンドラーを使用します。 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" + "streamhandler。Checkclasspath。" + cfe.toString());} //ストリームハンドラファクトリが//すでに正常に設定されている場合//フラグが設定されていることを確認し、エラーcatch(Error err){m_bStreamHandlerSet = true;}}を使用します。 // JSSEハンドラーを使用してみてください。 //注:JSSEには1.2以上が必要ですelse if(1.2 <= dVersion.doubleValue()){System.setProperty( "java.protocol.handler.pkgs"、 "com.sun.net.ssl.internal.www.protocol "); try {// JSSEプロバイダーが利用可能であり、//まだ設定されていない場合は、それを新しいプロバイダーとしてSecurityクラスに追加します。クラス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 JSSE SSL streamhandler。" + "クラスパスを確認してください。" + cfe.toString()); }}

アプレットはどうですか?

アプレット内からHTTPSベースの通信を実行することは、上記のシナリオの自然な拡張のように思われます。実際には、ほとんどの場合、それはさらに簡単です。NetscapeNavigatorおよびInternetExplorerの4.0以降のバージョンでは、HTTPSはそれぞれのVMでデフォルトで有効になっています。したがって、アプレットコード内からHTTPS接続を作成する場合は、URLクラスのインスタンスを作成するときにプロトコルとしてHTTPSを指定するだけです。

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

クライアントブラウザがSunのJava2プラグインを実行している場合、HTTPSの使用方法には追加の制限があります。Java 2プラグインでのHTTPSの使用に関する完全な説明は、SunのWebサイトにあります(「参考文献」を参照)。

結論

アプリケーション間でHTTPSプロトコルを使用すると、通信で妥当なレベルのセキュリティを取得するための迅速かつ効果的な方法になります。残念ながら、標準のJava仕様の一部としてサポートされていない理由は、技術的というよりも合法であるように思われます。ただし、JSSEの登場とMicrosoftのcom.ms.net.winintパッケージの使用により、ほとんどのプラットフォームから数行のコードで安全な通信が可能になりました。

自称eBozoであるMattTowersは、最近、Visioで開発職を辞めました。それ以来、彼はワシントン州シアトルのインターネットスタートアップPredictPoint.comに参加し、フルタイムのJava開発者として働いています。

このトピックの詳細

  • The source code zip file for this article contains the platform-independent code shown above implemented in a class called HttpsMessage. HttpsMessage is intended as a subclass to the HttpMessage class written by Jason Hunter, author of Java Servlet Programming (O'Reilly & Associates). Look for HttpsMessage in the upcoming second edition of his book. If you wish to use that class as intended, you'll need to download and install the com.oreilly.servlets package. The com.oreilly.servlets package and corresponding source code can be found on Hunter's Website

    //www.servlets.com

  • You can also download the source zip file

    //images.techhive.com/downloads/idge/imported/article/jvw/2000/06/httpsmessage.zip

  • Here are a few good Webpages for testing HTTPS communication:
  • //www.verisign.com/
  • //happiness.dhs.org/
  • //www.microsoft.com
  • //www.sun.com
  • //www.ftc.gov
  • More information on the JSSE as well as the downloadable bits and installation instructions can be found on Sun's Website

    //java.sun.com/products/jsse/.

  • A description of how to use some JSSE services, including the technique described above, can be found in "Secure Networking in Java" by Jonathan Knudsen on the O'Reilly Website

    //java.oreilly.com/bite-size/java_1099.html

  • More information on WininetStreamHandlerFactory class can be found in the Microsoft JSDK documentation

    //www.microsoft.com/java/sdk/. In addition, the Microsoft knowledge base also publishes "PRBAllowing the URL class to access HTTPS in Applications"

    //support.microsoft.com/support/kb/articles/Q191/1/20.ASP

  • For more information on using HTTPS with the Java 2 plug-in, see "How HTTPS Works in Java Plug-In" on Sun's Website

    //java.sun.com/products/plugin/1.2/docs/https.html

このストーリー「JavaTip96:JavaクライアントコードでHTTPSを使用する」は、もともとJavaWorldによって公開されました。