CSRF対策とJavaのHTTPクライアント
CSRF対策されたhttpsページをJavaのクライアントで自動取得しようとしてはまりました。対策の内容としては、一ページ目の中には動的に生成されるhiddenパラメータが含まれ、同じページでクッキーを設定して、次のクエリでパラメータとクッキーの内容を照合するというものです。
なんとなく作ったjava.net.URLを使ったクライアントではダメでした。一ページ目をwgetで取得して、httpヘッダーを含むクエリをテキストファイルで作って、JavaのSSLのクライアントを作った所OKでした。でその後wgetで取得したデータを上記なんとなく作ったクライアントで試した所OKでした。ということでなんとなく作ったクライアントの一ページ目の取得がおかしいという事になりました。HTTPSなので詳細が見れませんので、しょうがないのでPAROSでMITMしてみたところ、なぜかページの取得が2度行われていました。
で結論なのですが、ヘッダーを取るためにURLConnectionが必要だったのですが、
URL url = new URL(url); URLConnection con = url.openConnection(); //1度目のアクセス Inputstream in = url.openStream(); //2度目のアクセス
としていたためでした。
URL url = new URL(url); URLConnection con = url.openConnection();//1度目のアクセス Inputstream in = con.getInputStream(); //1度目アクセスののストリーム
で解決。備忘録にJavaのSSLで証明書検証を無視するおまじないを書いておきます。
import javax.net.ssl.*; import java.security.cert.*; import java.security.*; ... 中略 ... SSLContext tSSLContext = SSLContext.getInstance("SSL"); tSSLContext.init(null, new TrustManager { new X509TrustManager() { public void checkClientTrusted(X509Certificate aCertificates, String aString) throws CertificateException { } public void checkServerTrusted(X509Certificate aCertificates, String aString) throws CertificateException { } public X509Certificate getAcceptedIssuers() { return null; } } }, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(tSSLContext.getSocketFactory()); HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String aHostname, SSLSession aSession) { return true; } });