Apacheでクライアント認証をおこない、Javaプログラムで証明書情報を取得して解析

apache

Apacheを使ったWEBアプリケーションでSSL通信をおこなうためには、Apacheが認識するサーバのフォルダ上に証明書を格納し、Apacheの設定ファイルに証明書の情報を定義する必要があります。

かつ、より安全なSSL通信をおこなう方法は、クライアント認証をおこなう方法になります。

許可した端末のブラウザにクライアント証明書をインストールし、そのクライアント証明書がインストールされている端末についてのみSSL通信を許可します。


今回は、クライアント証明書を使ってSSL通信をおこなうための設定方法と、クライアント証明書から情報を抜き出すJavaプログラムについて説明します。


環境情報


  • HTTPサーバ:Apahce2.2.15
  • 言語:Java1.7.79

SSL認証の概要


クライアント証明書を用いたSSL通信は、通常のSSL通信と少し異なります。

SSL通信をおこなう端末のブラウザにクライアント証明書をインストールしておき、通信においてブラウザのクライアント証明書と、サーバ側のルート証明書とで証明書のマッチング認証をおこない、同証明書であればSSL通信を許可します。



上記のクライアント証明書を用いたSSL通信をおこなうためには、ブラウザへのクライアント証明書のインストールと、Apacheへの証明書設定の2つが必要になります。


Apacheへの証明書設定(サーバ側)


サーバ側の証明書設定は、通常、証明書発行局が作成した証明書をサーバ上に指定フォルダに格納し、Apacheの設定ファイルに証明書のパスを設定します。
OpenSSLを使って独自で証明書を作成した場合でも設定方法は同様です。


設定するファイルは「ssl.conf」になります。
設定箇所は以下の4つです。


SSLCertificateFile サーバ証明書の格納パス
SSLCertificateKeyFile 秘密鍵の格納パス
SSLCertificateChainFile サーバー証明書の中間証明書格納パス
SSLCACertificateFile クライアント証明書のルート証明書格納パス

# サーバー証明書
SSLCertificateFile /etc/httpd/cert/server.crt

# 秘密鍵
SSLCertificateKeyFile /etc/httpd/cert/secret.key

# サーバー証明書における中間証明書
SSLCertificateChainFile /etc/httpd/cert/publicKey.cer

# クライアント証明書におけるルート証明書
SSLCACertificateFile /etc/httpd/cert/root.pem

設定する証明書によっては、証明書の形式も意識する必要があります。
例えば、クライアント証明書におけるルート証明書(SSLCACertificateFile)は、テキスト形式でなくてはなりません。

Apacheのバージョンによるかもしれないのですが、少なくとも「Apahce2.2.15」ではバイナリ形式のルート証明書は認識できません。


Apacheのエラーログに、以下のログが出力されてApacheの起動に失敗します。


[Thu Mon DD HH:MI:SS YYYY] [info] SSL Library Error: 336105671error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not  return a certificate No CAs known to server for verification? 

証明書発行局からテキスト形式の証明書を発行してもらうことが一番よいのですが、OpenSSLコマンドを用いてバイナリからテキスト形式への変更も可能です。


openssl x509 -inform der -in root.cer -outform pem -out root.pem 

ブラウザへの証明書インストール(クライアント側)


ブラウザにインストールするクライアント証明書も、サーバ証明書と同様に証明書発行局が作成した証明書をインストールします。

こちらも基本的には、ウィザードに沿ってブラウザに証明書をインストールしていきます。


証明書ファイル(.der、など)をクリックすると、以下のようなインストールウィザードがひらきます。

表示内容を確認し、OKボタンを押下します。



保管場所を選択します。

通常であれば「現在のユーザ」でよいです。

選択したら次へボタンを押下します。



証明書ストアを設定します。

何かしらの理由がなければ、自動ストアを選択して、次へボタンを押下します。


以下のウィンドウが表示されれば、無事にクライアント証明書のインストール完了です。



インストールが完了したら、ブラウザの設定ウィンドウをひらいてインストール結果を確認します。

Edge(Chromium版)での確認方法は、設定ウィンドウをひらき、「プライバシーとサービス」→「証明書の管理」で証明書情報を確認できます。



「個人」タブにインストールした証明書が表示されていれば、正常にクライアント証明書が認識されているという事になります。


証明書から情報を取得


クライアント証明書を使ったSSL通信において、WEBアプリケーション側でクライアント証明書を情報を取得する事も可能です。
具体的には、JavaプログラムでHTTPリクエストから抽出します。


以下のプログラムでは、java.security.cert.X509Certificateを使って、HttpServletRequestから識別情報を取得しています。


private void getCert(HttpServletRequest request) {

    // -- クライアント証明書情報の取得 --//
    java.security.cert.X509Certificate[] certs = 
        (java.security.cert.X509Certificate[]) request.getAttribute(
        "javax.servlet.request.X509Certificate");

    // クライアント証明書からクライアント証明書識別子を取得
    Principal principal = certs[0].getSubjectX500Principal();

    // クライアント証明書識別子を取得
    X509Name name = new X509Name(principal.getName());
    Vector<?> cert = 
        name.getValues(X509ObjectIdentifiers.commonName);
    if (cert.size() == 1) {
        String code = cert.get(0);
    }

上記のプログラムで、クライアント証明書に格納されている「commonName」を取得することができます。


上記プログラムの用途としては、インストールされているクライアント証明書に格納されている情報(commonName)毎にアプリケーションの制御を変える場合です。
クライアント証明書Aをインストールしているブラウザからログインしたユーザと、クライアント証明書Bをインストールしているブラウザからログインしたユーザとで、上記で取得した情報をもとに制御の切替が可能となります。



sakusaku

都内でSIerをやっています。 使用している技術は、Java、PHP、MySQL、PostgreSQL、Oracle、Apache、Tomcat、あたりです。 Pythonやってみたいです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください