5. ネットワーク通信要件

5.1. MSTG-NETWORK-1

データはネットワーク上でTLSを使用して暗号化されている。セキュアチャネルがアプリ全体を通して一貫して使用されている。

5.1.1. 安全なネットワークリクエスト

5.1.1.1. 推奨されるネットワーク API の使い方

まず、ソースコード内ですべてのネットワークリクエストを特定し、平文の HTTP URL が使用されていないことを確認する必要がある。機密情報は、HttpsURLConnection または SSLSocket (TLS を使用したソケットレベルの通信用 ) を使用して、安全なチャネルで送信されるようにする。

次に、セキュアな接続を行うことを前提とした低レベルの API (SSLSocket など) を使用する場合でも、セキュアな実装が必要であることに注意する。例えば、SSLSocket はホスト名を検証しない。ホスト名を確認するには getDefaultHostnameVerifier を使用する。コード例は Android の開発者向けドキュメントを参照する。

参考資料

ルールブック

5.1.1.2. 平文の HTTP トラフィックの設定

次に、アプリが平文の HTTP トラフィックを許可していないことを確認する必要がある。 Android 9 ( API level 28 ) 以降、平文の HTTP トラフィックはデフォルトでブロックされる( デフォルトのネットワークセキュリティ構成によって )が、アプリが平文を送信する方法はまだ複数ある。

  • AndroidManifest.xml ファイルの <application> タグの android:usesCleartextTraffic 属性を設定する。Network Security Configuration が設定されている場合、このフラグは無視されることに注意する。

  • <domain-config> 要素で cleartextTrafficPermitted 属性を true に設定し、 CleartextTraffic を有効にするように Network Security Configuration を設定する。

  • 低レベルの API (例: Socket ) を使用して、カスタム HTTP 接続を設定する。

  • クロスプラットフォームフレームワーク ( Flutter、Xamarin など ) を使用する。これらには通常、 HTTP ライブラリの独自の実装がある。

上記のすべてのケースは、全体として注意深く分析する必要がある。例えば、アプリが Android Manifest や Network Security Configuration で CleartextTraffic を許可していない場合でも、実際には HTTP トラフィックを送信している可能性がある。これは、低レベルの API ( Network Security Configuration が無視される ) を使用している場合や、クロスプラットフォームフレームワークが適切に設定されていない場合に起こり得る。

詳細については、「 HTTPS と SSL によるセキュリティ 」を参照。

参考資料

ルールブック

5.1.2. ルールブック

  1. 平文の HTTP URL が使用されていないことを確認する(必須)

  2. 機密情報は安全なチャネルで送信されるようにする(必須)

  3. 低レベルの API を使用したセキュアな実装(必須)

  4. アプリが平文の HTTP トラフィックを許可していないことを確認する(必須)

5.1.2.1. 平文の HTTP URL が使用されていないことを確認する(必須)

ソースコード内ですべてのネットワークリクエストを特定し、平文の HTTP URL が使用されていないことを確認する必要がある。

これに違反する場合、以下の可能性がある。

  • 平文情報が第三者に漏洩する。

5.1.2.2. 機密情報は安全なチャネルで送信されるようにする(必須)

危険なチャネル( HTTP )により機密情報を送信すると、平文のまま送信されることにより第三者へ漏洩する可能性がある。そのため、機密情報を送信する場合は安全なチャネル( HTTPS、SSL 等)で送信する必要がある。

以下に安全なチャネルで送信するためのサンプルコードを示す。

  • HttpsURLConnection

    val url = URL("https://gmail.com:433/")
    val urlConnection = url.openConnection() as HttpsURLConnection
    urlConnection.connect();
    
  • SSLSocket

    val socket: SSLSocket = SSLSocketFactory.getDefault().run {
        createSocket("gmail.com", 443) as SSLSocket
    }
    

これに違反する場合、以下の可能性がある。

  • 機密情報が第三者に漏洩する。

5.1.2.3. 低レベルの API を使用したセキュアな実装(必須)

低レベルの API を使用する場合でも、セキュアな実装が必要である。 SSLSocket はホスト名を検証しない。ホスト名を確認するには getDefaultHostnameVerifier を使用する。

以下は SSLSocket 使用時のホスト名検証サンプルコードの一例。

    // Open SSLSocket directly to gmail.com
    val socket: SSLSocket = SSLSocketFactory.getDefault().run {
        createSocket("gmail.com", 443) as SSLSocket
    }
    val session = socket.session

    // Verify that the certicate hostname is for mail.google.com
    // This is due to lack of SNI support in the current SSLSocket.
    HttpsURLConnection.getDefaultHostnameVerifier().run {
        if (!verify("mail.google.com", session)) {
            throw SSLHandshakeException("Expected mail.google.com, found ${session.peerPrincipal} ")
        }
    }

    // At this point SSLSocket performed certificate verification and
    // we have performed hostname verification, so it is safe to proceed.

    // ... use socket ...
    socket.close()
    

これに違反する場合、以下の可能性がある。

  • 通信先ホストが信頼できるか保証されない可能性がある。

5.1.2.4. アプリが平文の HTTP トラフィックを許可していないことを確認する(必須)

アプリが平文の HTTP トラフィックを許可していないことを確認する。 Android 9 ( API level 28 ) 以降、平文の HTTP トラフィックはデフォルトでブロックされるが、アプリが平文を送信する方法は複数存在する。

以下はアプリから平文を送信する方法の一例。

  • AndroidManifest.xml ファイルの <application> タグの android:usesCleartextTraffic 属性を設定する。Network Security Configuration が設定されている場合、このフラグは無視されることに注意する。

    <application
                android:usesCleartextTraffic="true">
    </application>
    
  • <domain-config> 要素で cleartextTrafficPermitted 属性を true に設定し、 CleartextTraffic を有効にするように Network Security Configuration を設定する。

    <?xml version="1.0" encoding="utf-8"?>
    <network-security-config>
        <base-config cleartextTrafficPermitted="false" />
        <domain-config cleartextTrafficPermitted="true">
            <domain includeSubdomains="true">secure.example.com</domain>
        </domain-config>
    </network-security-config>
    
  • 低レベルの API (例: Socket ) を使用して、カスタム HTTP 接続を設定する。

    val address = InetSocketAddress(ip, port)
    val socket = Socket()
    try {
        socket.connect(address)
    } catch (e: Exception) {
    }
    
  • クロスプラットフォームフレームワーク ( Flutter、Xamarin など ) を使用する。これらには通常、 HTTP ライブラリの独自の実装がある。

これに違反する場合、以下の可能性がある。

  • HTTP トラフィックにより平文を送信する。

5.2. MSTG-NETWORK-2

TLS 設定は現在のベストプラクティスと一致している。モバイルオペレーティングシステムが推奨される標準規格をサポートしていない場合には可能な限り近い状態である。

5.2.1. 推奨される TLS 設定

サーバ側で適切な TLS 設定を行うことも重要である。 SSL プロトコルは非推奨であり、もはや使用するべきではない。また、 TLS v1.0 と TLS v1.1 には既知の脆弱性があり、 2020 年までにすべての主要なブラウザでその使用が非推奨となった。 TLS v1.2 および TLS v1.3 は、安全なデータ通信のためのベストプラクティスと考えられている。

Android 10(API level 29) 以降では、TLS v1.3 がデフォルトで有効になり、より高速で安全な通信が可能になる。 TLS v1.3 の主な変更点は、暗号スイートのカスタマイズができなくなり、 TLS v1.3 を有効にするとすべての暗号スイートが有効になるのに対し、 0-RTT(Zero Round Trip) モードがサポートされない。

クライアントとサーバの両方が同じ組織で管理され、互いに通信するためだけに使用されている場合、設定を強化することでセキュリティを強化できる。

モバイルアプリケーションが特定のサーバに接続する場合、そのネットワークスタックを調整することで、サーバの構成に対して可能な限り高いセキュリティレベルを確保することができる。オペレーティングシステムのサポートが不十分な場合、モバイルアプリケーションはより弱い構成を使用せざるを得なくなる可能性がある。

参考資料

ルールブック

5.2.2. 推奨される暗号スイート

暗号スイートの構造は以下の通りである。

Protocol_KeyExchangeAlgorithm_WITH_BlockCipher_IntegrityCheckAlgorithm

この構造には以下が含まれる。

  • 暗号化で使用されるプロトコル

  • TLS ハンドシェイク中にサーバとクライアントが認証に使用する鍵交換アルゴリズム

  • メッセージストリームの暗号化に使用されるブロック暗号

  • メッセージの認証に使用される完全性保証チェックアルゴリズム

例: TLS_RSA_WITH_3DES_EDE_CBC_SHA

上記の例では、以下の暗号化スイートが使用されている。

  • プロトコルとしての TLS

  • 認証のための RSA 非対称暗号化

  • EDE_CBC モードによる対称暗号化のための 3DES

  • 完全性のための SHA ハッシュアルゴリズム

TLSv1.3 では、鍵交換アルゴリズムは暗号スイートの一部ではなく、TLS ハンドシェイク中に決定されることに注意する。

次のリストでは、暗号スイートの各部分のさまざまなアルゴリズムを紹介する。

プロトコル :

鍵交換アルゴリズム :

ブロック暗号 :

完全性チェックアルゴリズム :

暗号スイートの効率は、そのアルゴリズムの効率に依存することに注意する必要がある

以下のリソースは、 TLS で使用するために推奨される最新の暗号スイートが含まれている。

Android の一部バージョンでは、推奨する暗号スイートに対応していないものもあるため、互換性のために、 Android のバージョンでサポートされている暗号スイートを確認し、上位の暗号スイートを選択することが可能である。

サーバが適切な暗号スイートをサポートしているかどうかを確認する場合は、さまざまなツールを使用できる。

  • testssl.sh は、「 TLS/SSL 暗号、プロトコル、およびいくつかの暗号の欠陥のサポートについて、任意のポートでサーバのサービスをチェックする無料のコマンドラインツール」である。

最後に、 HTTPS 接続が終了するサーバまたは終了プロキシが、ベストプラクティスに従って設定されていることを確認する。 OWASP Transport Layer Protection cheat sheet および Qualys SSL/TLS Deployment Best Practices を参照する。

参考資料

ルールブック

5.2.3. ルールブック

  1. 安全な通信プロトコル(必須)

  2. TLS で推奨される暗号化スイート(推奨)

5.2.3.1. 安全な通信プロトコル(必須)

サーバ側で適切な TLS 設定を行うことも重要である。 SSL プロトコルは非推奨であり、もはや使用するべきではない。

非推奨プロトコル

  • SSL

  • TLS v1.0

  • TLS v1.1

TLS v1.0 と TLS v1.1 については、2020 年までにすべての主要なブラウザでその使用が非推奨となった。

推奨プロトコル

  • TLS v1.2

  • TLS v1.3

Android 10(API level 29) 以降では、TLS v1.3 がデフォルトで有効になり、より高速で安全な通信が可能になる。 TLS v1.3 を有効にするとすべての暗号スイートが有効になるのに対し、 0-RTT(Zero Round Trip) モードがサポートされない。

これに違反する場合、以下の可能性がある。

  • セキュリティエクスプロイトに対して脆弱である。

5.2.3.2. TLS で推奨される暗号化スイート(推奨)

以下は推奨される暗号化スイートの一例。(TLS Cipher Suites で推奨されている暗号化スイートの中で、Androidで非推奨ではないものを記載。)

  • TLS_DHE_PSK_WITH_AES_128_GCM_SHA256

  • TLS_DHE_PSK_WITH_AES_256_GCM_SHA384

  • TLS_AES_128_GCM_SHA256

  • TLS_AES_256_GCM_SHA384

  • TLS_CHACHA20_POLY1305_SHA256

  • TLS_AES_128_CCM_SHA256

  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384

  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

  • TLS_DHE_RSA_WITH_AES_128_CCM

  • TLS_DHE_RSA_WITH_AES_256_CCM

  • TLS_DHE_PSK_WITH_AES_128_CCM

  • TLS_DHE_PSK_WITH_AES_256_CCM

  • TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

  • TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256

  • TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256

  • TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256

  • TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256

  • TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256

  • TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384

  • TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256

これに注意しない場合、以下の可能性がある。

  • 脆弱な暗号化スイートを使用する可能性がある。

5.3. MSTG-NETWORK-3

セキュアチャネルが確立されたときに、アプリはリモートエンドポイントの X.509 証明書を検証している。信頼された CA により署名された証明書のみが受け入れられている。

5.3.1. 信頼する証明書の設定

5.3.1.1. ターゲット SDK バージョンごとのデフォルト設定

Android 7.0 (API level 24) 以降をターゲットとするアプリケーションは、ユーザが提供する CA を信頼しないデフォルトのネットワークセキュリティ構成を使用し、ユーザを誘い込んで悪意のあるCAをインストールさせる MITM 攻撃の可能性を低減する。

apktool を使用してアプリをデコードし、 apktool.yml の targetSdkVersion が 24 以降であることを確認する。

grep targetSdkVersion UnCrackable-Level3/apktool.yml
  targetSdkVersion: '28'

ただし、 targetSdkVersion >=24 の場合でも、開発者はカスタムネットワークセキュリティ構成を使用してデフォルトの保護を無効にし、ユーザが提供する CA をアプリに強制的に信頼させる custom trust anchor を定義することができる。 「カスタムトラストアンカーの分析」 を参照。

参考資料

ルールブック

5.3.1.2. カスタムトラストアンカーの分析

Network Security Configuration ファイルを検索し、 <certificates src="user"> を定義しているカスタムの <trust-anchors> を調査する ( これは避けるべきである ) 。

エントリの優先順位を慎重に分析する必要がある。

  • <domain-config> のエントリまたは親の <domain-config> に値が設定されていない場合、設定は <base-config> に基づいて行われる。

  • このエントリで定義されていない場合、デフォルトの設定が使用される。

Android 9 (API level 28) を対象とするアプリのネットワークセキュリティ構成の例は以下の通りである。

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="false">owasp.org</domain>
        <trust-anchors>
            <certificates src="system" />
            <certificates src="user" />
        </trust-anchors>
    </domain-config>
</network-security-config>

いくつかの考察を紹介する。 :

  • <base-config> がないため、Android 9 ( API level 28 ) 以降のデフォルト設定が他のすべての接続に使用される(原則としてシステム認証 CA のみが信頼される)。

  • しかし、 <domain-config> はデフォルトの設定を上書きし、指定された <domain> (owasp.org) に対して、アプリがシステムとユーザの両方の認証局を信頼することを可能にする。

  • includeSubdomains="false" のため、サブドメインには影響しない。

すべてをまとめると、上記のネットワークセキュリティ構成を次のように説明することができる。
「このアプリは、サブドメインを除く owasp.org ドメインのシステムとユーザの両方の認証局を信頼する。他のドメインでは、アプリはシステムの認証局のみを信頼する。」

参考資料

ルールブック

5.3.2. サーバ証明書の検証

5.3.2.1. TrustManager による検証

TrustManager は、 Android において信頼できる接続を確立するために必要な条件を確認する手段である。このとき、以下の条件を確認する必要がある。

  • 証明書は、信頼できる CA によって署名されているか?

  • 証明書の有効期限が切れていないか?

  • 自己署名の証明書であるか?

以下のコード スニペットは開発中に使用されることがあり、関数 checkClientTrusted, checkServerTrusted, getAcceptedIssuers をオーバーライドして、どんな証明書でも受け入れてしまう。このような実装は避けるべきであり、必要な場合は、組み込みのセキュリティ上の欠陥を回避するために、 production builds とは明確に分離する必要がある。

TrustManager[] trustAllCerts = new TrustManager[] {
    new X509TrustManager() {
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new java.security.cert.X509Certificate[] {};
        }

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        }
    }
 };

// SSLContext context
context.init(null, trustAllCerts, new SecureRandom());

参考資料

ルールブック

5.3.2.2. WebView でのサーバ証明書の検証

アプリケーションは WebView を使用して、アプリケーションに関連付けられた Web サイトをレンダリングすることがある。これは、アプリケーションのインタラクションに内部 WebView を使用する Apache Cordova などの HTML/JavaScript ベースのフレームワークに当てはまる。WebView が使用される場合、モバイルブラウザはサーバ証明書の検証を実行する。WebView がリモート Web サイトに接続しようとしたときに発生する TLS エラーを無視することは、バッドプラクティスである。

以下のコードは、 WebView に提供される WebViewClient のカスタム実装と全く同じように、TLS エラーを無視する。

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient(){
    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        //Ignore TLS certificate errors and instruct the WebViewClient to load the website
        handler.proceed();
    }
});

Apache Cordova フレームワークの内部 WebView 使用の実装は、 application manifest で android:debuggable フラグが有効になっていると、 onReceivedSslError メソッドで TLS エラーを無視する。そのため、アプリがデバッグ可能でないことを確認する。

参考資料

ルールブック

5.3.3. ホスト名の検証

クライアント側の TLS 実装におけるもう 1 つのセキュリティ上の欠陥は、ホスト名の検証の欠如である。開発環境は通常、有効なドメイン名ではなく内部アドレスを使用するため、開発者はホスト名の検証を無効にし(あるいはアプリケーションに任意のホスト名を許可させ)、アプリケーションが本番稼働するときに変更することを忘れてしまうことがある。
次のコードは、ホスト名検証を無効にするものである。

final static HostnameVerifier NO_VERIFY = new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
};

組み込みの HostnameVerifier を使用すると、任意のホスト名を受け入れることができる。

HostnameVerifier NO_VERIFY = org.apache.http.conn.ssl.SSLSocketFactory
                             .ALLOW_ALL_HOSTNAME_VERIFIER;

信頼できる接続を設定する前に、アプリケーションがホスト名を検証していることを確認する。

参考資料

ルールブック

5.3.4. ルールブック

  1. ターゲット SDK バージョンによる MITM 攻撃の可能性(必須)

  2. カスタムトラストアンカーの分析(必須)

  3. TrustManager による検証(必須)

  4. WebView でのサーバ証明書の検証のバッドプラクティス(必須)

  5. ホスト名の検証(必須)

5.3.4.1. ターゲット SDK バージョンによる MITM 攻撃の可能性(必須)

Android 7.0 (API level 24) 以降をターゲットとするアプリケーションは、ユーザが提供する CA を信頼しないデフォルトのネットワークセキュリティ構成を使用し、ユーザを誘い込んで悪意のあるCAをインストールさせる MITM 攻撃の可能性を低減する。

apktool を使用してアプリをデコードし、 apktool.yml の targetSdkVersion が 24 以降であることを確認する。

これに違反する場合、以下の可能性がある。

  • 悪意のあるCAをインストールさせる MITM 攻撃の可能性が高まる。

5.3.4.2. カスタムトラストアンカーの分析(必須)

targetSdkVersion >=24 の場合でも、開発者はカスタムネットワークセキュリティ構成を使用してデフォルトの保護を無効にし、ユーザが提供する CA をアプリに強制的に信頼させることをカスタムトラストアンカーで定義することができる。

AndroidManifest.xml に設定されている android:networkSecurityConfig の設定を確認する必要がある。

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:networkSecurityConfig="@xml/network_security_config"
                    ... >
        ...
    </application>
</manifest>

android:networkSecurityConfig に設定されている Network Security Configuration ファイルを確認して、以下のタグの状態を確認する必要がある。

  • <base-config>

  • <trust-anchors>

  • <certificates>

※ <certificates src="user"> の設定は避ける必要がある。

また、固有の構成で設定されていないタグは <base-config> での設定を継承し、 <base-config> が設定されていない場合はプラットフォームの既定値が設定される。

エントリの優先順位を慎重に分析する必要がある。

  • <domain-config> のエントリまたは親の <domain-config> に値が設定されていない場合、設定は <base-config> に基づいて行われる。

  • このエントリで定義されていない場合、デフォルトの設定が使用される。

Android 9 (API level 28) を対象とするアプリのネットワークセキュリティ構成の例は以下の通りである。

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="false">owasp.org</domain>
        <trust-anchors>
            <certificates src="system" />
            <certificates src="user" />
        </trust-anchors>
    </domain-config>
</network-security-config>

いくつかの考察を紹介する。 :

  • <base-config> がないため、Android 9 ( API level 28 ) 以降のデフォルト設定が他のすべての接続に使用される(原則としてシステム認証 CA のみが信頼される)。

  • しかし、 <domain-config> はデフォルトの設定を上書きし、指定された <domain> (owasp.org) に対して、アプリがシステムとユーザの両方の認証局を信頼することを可能にする。

  • includeSubdomains="false" のため、サブドメインには影響しない。

すべてをまとめると、上記のネットワークセキュリティ構成を次のように説明することができる。
「このアプリは、サブドメインを除く owasp.org ドメインのシステムとユーザの両方の認証局を信頼する。他のドメインでは、アプリはシステムの認証局のみを信頼する。」

これに違反する場合、以下の可能性がある。

  • 悪意のあるCAをインストールさせる MITM 攻撃の可能性が高まる。

5.3.4.3. TrustManager による検証(必須)

TrustManager を用いて関数 checkClientTrusted, checkServerTrusted, getAcceptedIssuers をオーバーライドした場合、以下サンプルコードのようにクライアント証明書の検証を行わずに全ての証明書を受け入れてしまうと、安全な通信を保証できない。開発時の場合には、以下サンプルコードにより自己証明書での動作確認が実施できて便利であるが、誤って製品版に組み込まれないようにするために処理を分けるべきである。

TrustManager[] trustAllCerts = new TrustManager[] {
    new X509TrustManager() {
        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new java.security.cert.X509Certificate[] {};
        }

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        }
    }
 };

// SSLContext context
context.init(null, trustAllCerts, new SecureRandom());

以下サンプルコードは、 特定の CA のセットを信頼するために、 TrustManager を初期化作成して HttpsURLConnection を設定する処理である。

    // Load CAs from an InputStream
    // (could be from a resource or ByteArrayInputStream or ...)
    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    // From https://www.washington.edu/itconnect/security/ca/load-der.crt
    InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
    Certificate ca;
    try {
        ca = cf.generateCertificate(caInput);
        System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
    } finally {
        caInput.close();
    }

    // Create a KeyStore containing our trusted CAs
    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);

    // Create a TrustManager that trusts the CAs in our KeyStore
    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);

    // Create an SSLContext that uses our TrustManager
    SSLContext context = SSLContext.getInstance("TLS");
    context.init(null, tmf.getTrustManagers(), null);

    // Tell the URLConnection to use a SocketFactory from our SSLContext
    URL url = new URL("https://certs.cac.washington.edu/CAtest/");
    HttpsURLConnection urlConnection =
        (HttpsURLConnection)url.openConnection();
    urlConnection.setSSLSocketFactory(context.getSocketFactory());
    InputStream in = urlConnection.getInputStream();
    copyInputStreamToOutputStream(in, System.out);
    

参考資料

これに違反する場合、以下の可能性がある。

  • 自己証明書での検証が含まれる場合、信頼できる証明書であるかの判断がつかない。

5.3.4.4. WebView でのサーバ証明書の検証のバッドプラクティス(必須)

アプリケーションは WebView を使用して、アプリケーションに関連付けられた Web サイトをレンダリングすることがある。これは、アプリケーションのインタラクションに内部 WebView を使用する Apache Cordova などの HTML/JavaScript ベースのフレームワークに当てはまる。WebView が使用される場合、モバイルブラウザはサーバ証明書の検証を実行する。WebView がリモート Web サイトに接続しようとしたときに発生する TLS エラーを無視することは、バッドプラクティスである。

以下のサンプルコードは、 TLS エラーを無視して WebViewClient に Web サイトをロードする処理の一例。

WebView myWebView = (WebView) findViewById(R.id.webview);
myWebView.setWebViewClient(new WebViewClient(){
    @Override
    public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
        //Ignore TLS certificate errors and instruct the WebViewClient to load the website
        handler.proceed();
    }
});

Apache Cordova フレームワークの内部 WebView 使用の実装は、 application manifest で android:debuggable フラグが有効になっていると、 onReceivedSslError メソッドで TLS エラーを無視する。そのため、アプリがデバッグ可能でないことを確認する。

これに違反する場合、以下の可能性がある。

  • 中間者攻撃に対して脆弱になる。

5.3.4.5. ホスト名の検証(必須)

開発段階において、開発者はホスト名の検証を無効(あるいはアプリケーションに任意のホスト名を許可させ)にして開発を行っていることがある。 本番環境稼働時に変更せず検証を無効としていることがある。

以下は、無効としている場合のものである。

final static HostnameVerifier NO_VERIFY = new HostnameVerifier() {
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
};

以下は、任意のホスト名を受け入れるようにしたものである。

HostnameVerifier NO_VERIFY = org.apache.http.conn.ssl.SSLSocketFactory
                             .ALLOW_ALL_HOSTNAME_VERIFIER;

本番環境接続時にホスト名の検証を行う必要がある。

これに違反する場合、以下の可能性がある。

  • ホスト先が信頼される宛先のホストでは無い状態で通信する可能性がある。