オレオレHTTPSにJavaから接続するメモ

2014-01-07T00:00:00+00:00 Java

※以下の手法を使うとセキュリティ問題になる原因になるので注意

適当にnginxでオレオレ証明書を使ってHTTPSサーバーを構築した。じゃあそれをJavaで接続してみよう

import java.net.URL;
import javax.net.ssl.HttpsURLConnection;

public class Client {
    public static void main(String[] args) throws Exception {

        URL url = new URL("https://localhost");
        HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
        conn.setDoOutput(true);

        System.out.println(conn.getResponseCode());
    }
}

ってなことをすると

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

的なエラーが出て処理出来ない

てな訳でそれを解決する方法が今の所だと2つ

方法1. keytoolで証明書を信頼するように追加

keytool \
    -import \
    -file /path/to/ssl.crt \
    -keystore "$JAVA_HOME/jre/lib/security/cacerts"

alias指定してないけど指定しなかったらmykeyっていうaliasになる模様。-importじゃなくて-deleteにすれば消すのも可能

設定したら上記のコードをそのまま動かす。問題無ければ例外出ずにステータスコードが出る

参考: http://shinodogg.com/?p=3849

方法2. 証明書承認要求?を無視する

※以下のコードを利用するとセキュリティ脆弱性になるので可能な限り避けるべきかと

import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

public class Client {
    public static void main(String[] args) throws Exception {
        TrustManager[] tm = {
            new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

                public void checkClientTrusted(X509Certificate[] xc,String type) {
                }

                public void checkServerTrusted(X509Certificate[] xc,String type) {
                }
            }
        };

        SSLContext ctx = SSLContext.getInstance("SSL");
        ctx.init(null, tm, new SecureRandom());

        URL url = new URL("https://localhost");
        HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
        conn.setDoOutput(true);
        conn.setSSLSocketFactory(ctx.getSocketFactory());


        System.out.println(conn.getResponseCode());
    }
}

余談

Androidの場合には公式にドキュメントがあるのでそれ参考

http://developer.android.com/training/articles/security-ssl.html

Spring WebMVCのformとFormatterの件 mock-javamail