Javaでhttps通信時の証明書検証について

JavaからHTTP接続する際に行われる検証

https接続する際には、以下の2つの検証が行われる。

(1) 証明書/認証局の検証 ・・・ 有効な証明書か。(信頼できる認証局によって署名された証明書か)
(2) サーバ名の検証 ・・・ 証明書に書かれているホスト名と、アクセス先のホスト名が一致しているか。

検証を通過させる為のコード

テスト環境等で、まっとうな証明書がインストールされたサーバがない場合、以下のように証明書の検証をスルーする事ができる。
ただし、この方法は結構な注意換気が行われているので、本番リリースに含めるのは控えた方が良い。(Androidアプリ等は特に)

以下は、Android関連の注意換気、ガイド等
https://www.ipa.go.jp/about/press/20140919_1.html
http://www.slideshare.net/jpcert_securecoding/cert-verif-javadaytokyo2015
https://www.jssec.org/dl/android_securecoding.pdf


    /**
     * HTTPS通信
     */
    private void sendHttpsRequest(String uri, String method, Map param) {

            URL urlObj = new URL(uri);
            HttpURLConnection http = (HttpsURLConnection) urlObj.openConnection();

            // デフォルトのホスト名検証ルールを設定
            setDefaultHostnameVerifier();

            // 証明書情報を取得
            TrustManager[] tm = getTrustManager();
            SSLContext sslcontext = SSLContext.getInstance("SSL");
            sslcontext.init(null, tm, null);

            // 空の証明書情報が設定されたオブジェクトをセット
            ((HttpsURLConnection) http).setSSLSocketFactory(sslcontext.getSocketFactory());

             .
             .
             .
    }

    /**
     * 信頼する証明書情報を取得する。<br />
     * @return 証明書情報
     */
    private TrustManager[] getTrustManager() {

        TrustManager[] tm = {new X509TrustManager() {
            @Override
            public void checkClientTrusted(
                    java.security.cert.X509Certificate[] chain,
                    String authType) throws CertificateException {
                   // 何も検証しない
            }

            @Override
            public void checkServerTrusted(
                    java.security.cert.X509Certificate[] chain,
                    String authType) throws CertificateException {
                   // 何も検証しない
            }

            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                // 証明書情報として空を返す(つまり検証を行わない)
                return null;
            }
        } }; 
        return tm;
    } 

    /**
     * https通信時のデフォルトのホスト名検証ルールを設定する<br />
     */
    private void setDefaultHostnameVerifier() {
        // テスト用なので全てtrueを返す(つまり検証を行わない)
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String hostname, SSLSession session) {
                return true;
            } 
        }); 
    } 

検証を通過させる為のコードを書かない為のテスト環境構築

上記のコードを書かない為に、できるだけ本番に近い環境構築を行う方法を記載する。
※ただし、本番ではまっとうな認証局に署名された正式な証明書を利用し、普通に名前解決ができるドメインを取得した方が良い。

署名用の自己認証局(CA)の作成

mkdir -p /var/certs/myCA
cd /var/certs/myCA
mkdir private
mkdir newcerts
chmod 700 private
echo 01>serial
touch index.txt
sudo openssl req -new -x509 -newkey rsa:2048 -out myca.crt -keyout private/myca.key -days 365 -sha256

・
いろいろ聞かれるので入力する。
・

証明書情報の Organization Name が認証局と一致していなくても署名できるようにする。

※オリジナルの openssl.cnf からコピーして作成する。

cd /var/certs
cp /etc/ssl/openssl.cnf ./

↓旧メモ
openssl.cnf

[ CA_default ]
#dir     = ./demoCA
dir     = ./myCA

[ policy_match ]
#organizationName = match
organizationName = optional

↓新メモ
openssl.cnf

[ca]
default_ca    = my_ca_default

[my_ca_default]
new_certs_dir = ./myCA/newcerts
database      = ./myCA/index.txt
serial        = ./myCA/serial
policy        = my_ca_policy
default_md    = md5 
default_days  = 365 

[my_ca_policy]
commonName             = supplied
countryName            = optional
stateOrProvinceName    = optional
localityName           = optional
organizationName       = optional
organizationalUnitName = optional
emailAddress           = optional

URLにIPアドレスを指定してアクセスする場合は以下の設定も追記
※IPアドレスでアクセスする場合は、証明書の Subject Alternative Name もチェックされるので、これを含む証明書を作成する必要がある。

vim openssl.cnf

[ v3_req ]
subjectAltName = @alt_names

[ alt_names ]
IP.1 = XXX.XXX.XXX.XXX      # 実際のIPアドレス

サーバ秘密鍵 及び 証明書署名要求(CSR)の作成

# サーバ秘密鍵の作成

openssl genrsa -des3 -out example_com.key 1024
Generating RSA private key, 1024 bit long modulus
.++++++
...............++++++
e is 65537 (0x10001)
Enter pass phrase for example_com.key:
Verifying - Enter pass phrase for example_com.key:

# サーバ秘密鍵のパスフレーズを解除(Apache自動起動用)

openssl rsa -in example_com.key -out example_com_nopass.key
Enter pass phrase for example_com.key:
writing RSA key

# サーバ証明書の署名要求(CSR)を作成

openssl req -new -sha256 -key example_com.key -out example_com.csr
・
・
いろいろ聞かれるので入力する。
(注意!)
Common Name、Organization Name は 実際のドメイン名と合わせておく事。(IPアドレスでアクセスする場合はIPアドレスをそのまま入力)
・
・

自己認証局で署名

sudo openssl ca -config ./openssl.cnf -md sha256 -cert myCA/myca.crt -keyfile myCA/private/myca.key -out example_com.crt -in example_com.csr

# IPアドレスでアクセスする場合は引数に -extensions v3_req も追加
#sudo openssl ca -config ./openssl.cnf -md sha256 -cert myCA/myca.crt -keyfile myCA/private/myca.key -out 192.168.1.10.crt -in 192.168.1.10.csr -extensions v3_req

・
・
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

Apache設定ファイルの編集

作成した鍵、サーバ証明書のpathを設定する(他のSSL周りの設定は ApacheでSSL(SNI)設定 等を参照 )

SSLCertificateFile /path_to/example_com.crt
SSLCertificateKeyFile /path_to/example_com_nopass.key

クライアント端末へのインストール

上記で作成したCA証明書(myca.crt)を対象の端末にインストールする。


トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2016-06-19 (日) 01:34:59 (2869d)