実際に脆弱性のあるソースコードを確認し、修正してみましょう。
まず、「ソースコードを開く」ボタンをクリックし、「
MainActivity.java」を開いてください。
ソースコードを開く
修正前:
プロジェクト |
SSLConnection |
ソースファイル |
MainActivity.java |
try {
//Private証明書をassetsから読み込み、検証
KeyStore ks = KeyStoreUtil.getEmptyKeyStore();
KeyStoreUtil.loadX509Certificate(ks,
mContext.getResources().getAssets().open("server.crt"));
// ▼▼▼脆弱性のあるソースコード▼▼▼
// 1.独自でTrustManagerを実装したクラス(PrivateSSLSocketFactory)を実装
// 2.HostnameVerifierにSSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIERをセット
SSLSocketFactory sslSocketFactory = new PrivateSSLSocketFactory(ks);
sslSocketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Scheme sch = new Scheme("https", sslSocketFactory, 443);
// ▲▲▲脆弱性のあるソースコード▲▲▲
client.getConnectionManager().getSchemeRegistry().register(sch);
HttpGet request = new HttpGet(params[0]);
HttpResponse response = client.execute(request);
webView.loadData(EntityUtils.toString(response.getEntity()), "text/html", "UTF-8");
// ▼▼▼脆弱性のあるソースコード▼▼▼
} catch (Exception e) {
}
// ▲▲▲脆弱性のあるソースコード▲▲▲
return null;
}
|
このアプリには脆弱性対策を行うべき箇所が2箇所あります。修正例は以下の通りです。
-
ライブラリのインポート
この修正を行うには、下記のライブラリをインポートする必要があります。
修正中のMainActivity.javaの先頭にあるimport文の下に、以下のimport文を追加してください。
-
import javax.net.ssl.SSLException;
-
69~71行目
独自のTrustManagerとHostnameVerifierの使用を止め、標準のTrustManagerを使用するよう修正します。
このアプリで使用している独自のTrustManagerは
SSLExceptionを無視するよう設計されているため、中間者攻撃を受けた場合に
SSLExceptionを処理することができません。
標準のTrustManagerを使用することにより、
SSLExceptionを処理できるようになり、中間者攻撃を受けた際のエラー処理を行うことができるようになります。
69~70行目を削除し、71行目を以下のように修正します(赤文字部分)。
Scheme sch = new Scheme("https", new SSLSocketFactory(ks), 443);
-
81~82行目
SSLExceptionのcatchブロックを追加します。
71行目で標準のTrustManagerを使用するよう修正したことにより、
SSLExceptionを処理できるようになります。
中間者攻撃を受けた際に発生する
SSLExceptionを処理することにより、通信の中止や利用者への通知など、エラー処理を行えるようになります。
今回はサンプルアプリのため、処理をキャンセルするよう例外処理を実装していますが、開発するアプリに合わせ適切な例外処理を行うようにしましょう。
81行目と82行目の間に以下の処理を追加します。
}catch (SSLException e){
this.cancel(true);
修正後:
プロジェクト |
SSLConnection |
ソースファイル |
MainActivity.java |
try {
//Private証明書をassetsから読み込み、検証
KeyStore ks = KeyStoreUtil.getEmptyKeyStore();
KeyStoreUtil.loadX509Certificate(ks,
mContext.getResources().getAssets().open("server.crt"));
// ▼▼▼脆弱性を修正したソースコード▼▼▼
Scheme sch = new Scheme("https", new SSLSocketFactory(ks), 443);
// ▲▲▲脆弱性を修正したソースコード▲▲▲
client.getConnectionManager().getSchemeRegistry().register(sch);
HttpGet request = new HttpGet(params[0]);
HttpResponse response = client.execute(request);
webView.loadData(EntityUtils.toString(response.getEntity()), "text/html", "UTF-8");
// ▼▼▼脆弱性を修正したソースコード▼▼▼
} catch (SSLException e) {
this.cancel(true);
// ▲▲▲脆弱性を修正したソースコード▲▲▲
} catch (Exception e) {
}
return null;
}
|