web-dev-qa-db-ja.com

Webサービスとの相互認証

現在、ブラウザーがすべての証明書交換を処理するため、クライアントがWebブラウザーを使用してWebサイトにアクセスする限り、相互認証セキュリティの実装に成功しています。次に、サーバーに必要な相互認証を使用して、ユーザーがHTTPS経由でWebサービスにアクセスできる安全なインターフェースを作成する必要があります。

まず、誰かが知っているリソースで私がこれを助けることができるものはありますか?かなり長い間探しましたが何も見つかりませんでした。誰もがこれに対処する方法について私に与えることができる他のヒントはありますか?

第二に、私の最大の障害は、証明書の処理方法を理解していないことです。サーバーのキーを受け入れ、自分のキーをサーバーに提示するようにネゴシエートするにはどうすればよいですか?これはJavaです。

22
bkritzer

私はこれに長い時間を費やしましたが、ようやく実際に機能する例を見つけました。これはGlassfishとNetbeansベースですが、他の環境(EclipseやTomcatなど)で試してみれば、うまくいくと思います。

http://Java.Sun.com/webservices/reference/tutorials/wsit/doc/WSIT_Security9.html#wp162511

私が見つけた問題は、Glassfishがプリインストールされている証明書ではなく、独自の証明書を使用したい場合です。

注:私はセキュリティの専門家ではありません。これを本番環境にデプロイしないでください!

これを行うには、NetBeans 6.9、JDK 1.6、GlassFish 3.0.1、およびOpenSSL v1.0を使用しています(非公式のWin32バイナリを使用しています)。

# Create the CA
mkdir ca server client
cd ca
openssl req -new -x509 -days 3650 -extensions v3_ca -keyout ca.key -out ca.pem
echo 02 > serial.txt
cd ..

# Creating the Server Keystore

openssl req -days 3650 -newkey rsa:1024 -keyout server/server.key -out server/server.req
openssl x509 -extensions usr_cert -extfile C:\testbed\OpenSSL-Win32\bin\openssl.cfg -CA ca/ca.pem -CAkey ca/ca.key -CAserial ca/serial.txt -req -in server/server.req -out server/server.crt
openssl pkcs12 -export -inkey server/server.key -in server/server.crt -out server/server.p12 -name server
keytool -importkeystore -destkeystore server/server.jks -deststoretype jks -srckeystore server/server.p12 -srcstoretype pkcs12
keytool -exportcert -alias server -keystore server/server.jks -file server/server.cer

# Create the Client Keystore

openssl req -days 3650 -newkey rsa:1024 -keyout client/client1.key -out client/client1.req
openssl x509 -extensions usr_cert -extfile C:\testbed\OpenSSL-Win32\bin\openssl.cfg -CA ca/ca.pem -CAkey ca/ca.key -CAserial ca/serial.txt -req -in client/client1.req -out client/client1.crt
openssl pkcs12 -export -inkey client/client1.key -in client/client1.crt -out client/client1.p12 -name client1
keytool -importkeystore -destkeystore client/client1.jks -deststoretype jks -srckeystore client/client1.p12 -srcstoretype pkcs12
keytool -exportcert -alias client1 -keystore client/client1.jks -file client/client1.cer

# Import public keys and certificates into each others keystores

keytool -import -noprompt -trustcacerts -alias client1 -file client/client1.cer -keystore server/server.jks
keytool -import -noprompt -trustcacerts -alias server -file server/server.cer -keystore client/client1.jks
keytool -import -noprompt -trustcacerts -alias my_ca -file ca/ca.pem -keystore server/server.jks
keytool -import -noprompt -trustcacerts -alias my_ca -file ca/ca.pem -keystore client/client1.jks
keytool -import -noprompt -trustcacerts -alias my_ca -file ca/ca.pem -keystore "C:\Program Files\glassfish-3.0.1\glassfish\domains\domain1\config\cacerts.jks"
keytool -import -noprompt -trustcacerts -alias my_ca -file ca/ca.pem -keystore "C:\Program Files\Java\jdk1.6\jre\lib\security\cacerts"
move "C:\Program Files\glassfish-3.0.1\glassfish\domains\domain1\config\keystore.jks" "C:\Program Files\glassfish-3.0.1\glassfish\domains\domain1\config\keystore.jks.backup"
copy server\server.jks "C:\Program Files\glassfish-3.0.1\glassfish\domains\domain1\config\keystore.jks"

GlassFish管理コンソールで、http-リスナーのセキュリティを有効にし、SSL3、TLS、およびクライアント認証ボックスにチェックを入れ、証明書のニックネームをサーバーに、キーストアをconfig\keystore.jksに、トラストストアをconfig\keystore.jksに設定します。 、PKIXへの信頼アルゴリズム。証明書の最大長は5のままにします。

NetBeansで、新しいWebアプリケーションプロジェクトを作成します。その中に、新しいWebサービスを作成します。

私のWebサービスコードは次のようになりました。

@WebService()
public class ListProducts {

  @Resource WebServiceContext context;

  @WebMethod(operationName = "listProducts")
  public String listProducts() {
    return context.getUserPrincipal().toString();
  }

}

Webサービスを右クリックし、[Webサービス属性の編集]を選択します。 [セキュリティで保護されたサービス]ボックスをオンにして、セキュリティメカニズムとして[相互証明書セキュリティ]を選択します。 [構成...]ボタンをクリックし、[署名の暗号化]ボックスをオンにします。次に、[Use Development Defaults]ボックスをオフにして、[Keystore]ボタンをクリックします。 server.jksキーストアの場所を設定し、serverエイリアスを選択します。トラストストア構成についても同じようにします(ただし、ここでエイリアスを選択する必要はありません)。

Client1.p12クライアント証明書をブラウザーにインポートします。 WebサービスをGlassfishにデプロイします。ブラウザでWebサービスを開き、デプロイされたWSDLをHTTPS経由で参照します。 WSDLとその他のスキーマをダウンロードします。参照されているスキーマの名前をローカルコピーに変更して、WSDL2Java NetBeansを使用するときにリモートリソースを使用しないようにします。 (この段落は、WSDLを承認済みの証明書でクライアントに制限しているが、NetBeansは問題の証明書にアクセスできないため、リモートで取得できないためです)。

新しいJavaプロジェクトを作成します。新しいWebサービスクライアントを作成します。プロンプトが表示されたら、保存したWSDLファイルをNetBeansにポイントします。METRO2.0ライブラリファイル(C:\Program Files\Netbeans 6.9\enterprise\modules\ext\metr\webservices-*.jar)をインポートします。マイコードこのように見えた:

public static void main(String[] args) {
  System.getProperties().put("javax.net.ssl.keyStore", "C:\\NetBeansProjects\\security-04\\ssl\\client\\client1.jks");
  System.getProperties().put("javax.net.ssl.keyStorePassword", "changeit");
  System.getProperties().put("javax.net.ssl.trustStore", "C:\\NetBeansProjects\\security-04\\ssl\\client\\client1.jks");
  System.getProperties().put("javax.net.ssl.trustStorePassword", "changeit");
  System.out.println(new ListProductsService().getListProductsPort().listProducts());
}

Webservices-api.jarをJava\jdk1.6\jre\lib\endorsedディレクトリにコピーします。 Webサービス参照を右クリックし、[Webサービス属性の編集]を選択します。キーストアの場所をclient1.jksに設定し、エイリアスをclient1に設定します。トラストストアの場所をclient1.jksに設定し、エイリアスをserverに設定します。

うまくいけば、これでクライアントを実行でき、次のような出力が表示されるはずです:[email protected], CN=Bob Smith, OU=Something, O=SomethingElse, L=AnyTown, ST=AnyState, C=US

14
Catchwa

ブラウザーの外部でSSL(別名、双方向SSL)を使用した相互認証には、次のものが必要です。

  1. サーバーのキーストア
  2. クライアントのトラストストア

サーバーの鍵ストアには、サーバーの(自己署名の可能性がある)証明書と秘密鍵が含まれています。このストアは、サーバーがメッセージに署名し、資格情報をクライアントに返すために使用されます。

クライアントのトラストストアには、サーバーの(自己署名付き)証明書が含まれます(サーバーのキーストアからスタンドアロンの証明書に抽出され、サーバーの秘密鍵は含まれません)。これは、JREにバンドルされているトラストストアにすでに証明書がある証明書が信頼できるCAによって署名されていない場合に必要です。この手順により、信頼の連鎖を作成できます。

これにより、一方向SSL(従来の使用例)を実装できます。

双方向SSLを実装するには、この設定を「対称」にする必要があるため、以下を追加する必要があります。

  1. クライアントのキーストア
  2. サーバーのトラストストア

クライアントの鍵ストアには、クライアントの(おそらく自己署名された)証明書と秘密鍵が含まれています。このストアは、クライアントがサーバーのキーストアと同じ目的で使用します。つまり、TLS相互認証ハンドシェイク中にクライアントの資格情報をサーバーに送信します。

サーバーのトラストストアには、クライアント(自己署名)のスタンドアロン証明書(クライアントのキーストアからスタンドアロンの証明書に抽出され、クライアントの秘密鍵は含まれません)が含まれています。これは、前述したのとまったく同じ理由で必要です。

このすべてのものを生成し、最終的なソリューションを実装するのに役立ついくつかのリソース:

13
Pascal Thivent

Webサービスライブラリが標準のJava.net.URLクラスをHTTPクライアントとして使用する場合、いくつかの システムプロパティ を設定でき、双方向の認証は組み込みのHTTPSサポートによって処理されます。

必要なプロパティ は次のとおりです。

  • javax.net.ssl.trustStore:ルートCA証明書が含まれています
  • javax.net.ssl.keyStore:クライアント証明書と秘密鍵が含まれています
  • javax.net.ssl.keyStorePassword:クライアントの秘密鍵を保護するパスワード

これらの設定は、プロセスによるすべてのSSL接続のデフォルトになります。より細かく制御したい場合は、独自のSSLContextを設定する必要があります。 Webサービスランタイムでそれが可能かどうかは、選択したランタイムによって異なります。

6
erickson

簡単なレシピを このブログエントリ に示します。

しかし、本当の答えは、Javaクライアント側のHTTP対話を実装するために使用しているAPIに依存する可能性があると思います。たとえば、何かを行うように見えます JAX-RPCを使用します。

1
Stephen C