2つのアプリがあります。1つはサーブレット/ Tomcatサーバーで、もう1つはAndroidアプリです。
HttpURLConnectionを使用して、両方の間でXMLを送受信したいと思います。
コード:
private String sendPostRequest(String requeststring) {
DataInputStream dis = null;
StringBuffer messagebuffer = new StringBuffer();
HttpURLConnection urlConnection = null;
try {
URL url = new URL(this.getServerURL());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setDoOutput(true);
urlConnection.setRequestMethod("POST");
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
out.write(requeststring.getBytes());
out.flush();
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
dis = new DataInputStream(in);
int ch;
long len = urlConnection.getContentLength();
if (len != -1) {
for (int i = 0; i < len; i++)
if ((ch = dis.read()) != -1) {
messagebuffer.append((char) ch);
}
} else {
while ((ch = dis.read()) != -1)
messagebuffer.append((char) ch);
}
dis.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
urlConnection.disconnect();
}
return messagebuffer.toString();
}
ここで、SSLを使用してセキュリティのためにXMLを送信する必要があります。
まず、Java Keytoolを使用して.keystoreファイルを生成します。
Keytool -keygen -alias Tomcat -keyalg RSA
次に、SSLを使用するためにTomcatのserver.xmlファイルにXMLコードを配置します
<Connector
port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
keystoreFile="c:/Documents and Settings/MyUser/.keystore"
keystorePass="password"
clientAuth="false" sslProtocol="TLS"
/>
次に、HttpsURLConnectionのHttpURLConnectionに変更します
private String sendPostRequest(String requeststring) {
DataInputStream dis = null;
StringBuffer messagebuffer = new StringBuffer();
HttpURLConnection urlConnection = null;
//Conexion por HTTPS
HttpsURLConnection urlHttpsConnection = null;
try {
URL url = new URL(this.getServerURL());
//urlConnection = (HttpURLConnection) url.openConnection();
//Si necesito usar HTTPS
if (url.getProtocol().toLowerCase().equals("https")) {
trustAllHosts();
//Creo la Conexion
urlHttpsConnection = (HttpsURLConnection) url.openConnection();
//Seteo la verificacion para que NO verifique nada!!
urlHttpsConnection.setHostnameVerifier(DO_NOT_VERIFY);
//Asigno a la otra variable para usar simpre la mism
urlConnection = urlHttpsConnection;
} else {
urlConnection = (HttpURLConnection) url.openConnection();
}
//Do the same like up
すべてのサーバーを信頼するためにtrustAllHostsメソッドを追加します(証明書をチェックしないでください)
private static void trustAllHosts() {
X509TrustManager easyTrustManager = new X509TrustManager() {
public void checkClientTrusted(
X509Certificate[] chain,
String authType) throws CertificateException {
// Oh, I am easy!
}
public void checkServerTrusted(
X509Certificate[] chain,
String authType) throws CertificateException {
// Oh, I am easy!
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {easyTrustManager};
// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new Java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
}
これらの変更は非常にうまく機能しましたが、すべてのサーバーを信頼したくありません。キーストアファイルを使用して接続を検証し、SSLを正しい方法で使用したいと思います。私はインターネットでたくさん読んだり、たくさんのテストをしたりしましたが、自分が何をしなければならないのか、そしてそれをどのように行うのか理解できません。
誰かが私を助けることができますか?
どうもありがとうございました
英語が下手でごめんなさい
-------------------------更新2011/08/24 ------------------- ------------------------------
まあ、私はまだこれに取り組んでいます。 KeyStore、InputStreamなどを設定するための新しいメソッドを作成しました
メソッドは次のようになります。
private static void trustIFNetServer() {
try {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance("BKS");
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
String keyPassword = "password";
ks.load(in, keyPassword.toCharArray());
in.close();
tmf.init(ks);
TrustManager[] tms = tmf.getTrustManagers();
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, tms, new Java.security.SecureRandom());
} catch (Exception e) {
e.printStackTrace();
}
}
最初はキーと証明書に多くの問題がありましたが、現在は機能しています(そう思います)
今の私の問題はタイムアウト例外です。なぜ生成されるのかわかりません。データ書き込みの問題だと思いますが、まだ解決できません。
何か案が?
説明されているように、自己署名証明書用のトラストストアファイルを作成する必要があります ここ 。クライアント側で使用して、サーバーに接続します。 JKSと別の形式のどちらを使用するかは問題ではありませんが、ここではJKSを想定します。
念頭に置いていることを達成するには、明らかに別のTrustManager
が必要です。 TrustManagerFactory
を使用して、新しく作成したトラストストアでその信頼設定をフィードできます。
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream in = new FileInputStream("<path to your key store>");
ks.load(in, "password".toCharArray());
in.close();
tmf.init(ks);
TrustManager[] tms = tmf.getTrustManagers();
SSL/TLS接続に使用される新しい信頼設定の代わりに、tms
を使用してSSLContext
を初期化します。
また、サーバーのTLS証明書のCN
部分が、サーバーのFQDN(完全修飾ドメイン名)と等しいことを確認する必要があります。サーバーのベースURLが「 https://www.example.com 」の場合、証明書のCN
は「www.example.com」である必要があります。これは、man-in-the-middle攻撃を防ぐ機能であるホスト名の検証に必要です。これを無効にすることもできますが、これを使用する場合にのみ、接続は本当に安全になります。
すべての証明書を無視したい場合は、ハンドシェイクを無視してください。そうすれば、これは機能します: HttpsURLConnectionおよび断続的な接続
トラストストアを作成し、アセットとして保存し、それを使用してこれを初期化します SocketFactory 。次に、独自の「信頼するすべての人」の代わりにファクトリを使用します。