,

CSRF対策とJavaのHTTPクライアント

CSRF対策されたhttpsページをJavaのクライアントで自動取得しようとしてはまりました。対策の内容としては、一ページ目の中には動的に生成されるhiddenパラメータが含まれ、同じページでクッキーを設定して、次のクエリでパラメータとクッキーの内容を照合するというものです。
なんとなく作ったjava.net.URLを使ったクライアントではダメでした。一ページ目をwgetで取得して、httpヘッダーを含むクエリをテキストファイルで作って、JavaSSLのクライアントを作った所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度目アクセスののストリーム

で解決。備忘録にJavaSSLで証明書検証を無視するおまじないを書いておきます。

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;
 }
});