説明
すべての証明書を信頼したり、すべてのホスト名を許可したりすると、TLS接続が中間者攻撃に弱くなります。X509TrustManager の検証メソッドを空にする、または HostnameVerifier が常に true を返すと、サーバー認証に必要な検証が省略されます。
想定される影響
- 偽造した証明書でTLS接続を傍受されるおそれがあります。
- 機密データ、セッショントークン、APIのリクエストやレスポンスを盗聴・改ざんされる可能性があります。
- テスト用の検証回避設定が本番環境に残ると、通信の安全性が損なわれます。
対処方法
- 既定の信頼ストアと
HostnameVerifierを使用し、特定の環境だけ検証を無効にする運用を避けます。 - テストで自己署名証明書が必要な場合は、専用の信頼ストアを構成します。
- すべての証明書やホスト名を許可する独自の検証器やトラストマネージャーを使わないでください。
例
変更前
java
import javax.net.ssl.HttpsURLConnection;
public class UnsafeHostnameVerifier {
void configure(HttpsURLConnection conn) {
conn.setHostnameVerifier((hostname, session) -> true);
}
}
変更後
java
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
public class SafeTlsVerifier {
void configure(HttpsURLConnection conn) {
HostnameVerifier verifier = HttpsURLConnection.getDefaultHostnameVerifier();
conn.setHostnameVerifier(verifier);
}
}
説明:
- 変更前: どのホスト名でも
trueを返すため、証明書が接続先のサーバーに対応するかどうかの検証が省略されます。 - 変更後: 既定のホスト名検証器を使い、TLSライブラリの通常の検証処理を維持します。
ほかの検証回避設定
new X509TrustManager() { ... }のcheckClientTrustedやcheckServerTrustedを空にすると、対応する証明書の信頼性検証が省略されます。class AlwaysTrueVerifier implements HostnameVerifierという名前付きクラスでも、new HostnameVerifier() { ... return true; }という匿名クラスでも、常に許可する実装はホスト名検証を回避します。- Kotlinの
HostnameVerifier { _, _ -> true }にも同じ危険があります。object : HostnameVerifier { ... }やobject : X509TrustManager { ... }で実装する場合も、実際の検証が必要です。