Network Security Configurationについて - Android N
3月10日にAndroid NのPreview版がリリースされました。ようやくAndroid Mのセキュリティ回りの調査が一段落したと思っていたのに(全然調査内容ブログで書けてませんが…)もた調査の始まりですAndroid Mの時は、Runtime-Permissionという大きな機能が追加されました。現在ざっと見た感じ、NはMのような大きな変更はありませんが、それでも調査が必要な項目がいっぱいありました。皆さんマルチウインドウを色々試して盛り上がっているのを横目に、地味なセキュリティ回りの調査です。
今回のセキュリティ回りで目を引いたのが、「Network Secure Config」という機能です。
公開されているアンドロイドアプリは脆弱性がいっぱいですが、特にHTTPS通信の証明書の検査不備はひどいもので、IPAから注意喚起が出るほどです。
公開されているアンドロイドアプリは脆弱性がいっぱいですが、特にHTTPS通信の証明書の検査不備はひどいもので、IPAから注意喚起が出るほどです。
この脆弱性の対応策がNetwork Secure Config機能に入っています。
宣伝になりますが、ちなみに、この脆弱性はRiskFinderでも検知ができ以下のようなメッセージが表示されます。
宣伝になりますが、ちなみに、この脆弱性はRiskFinderでも検知ができ以下のようなメッセージが表示されます。
脆弱性が生み出される理由
さて、これらの脆弱性が生み出される理由は、何かというと、凡ミス、及び知っているか知っていないかの単純な知識不足です。
アンドロイドアプリの多くは、サーバと通信をします。ログイン等の処理があるときはhttpsを使用して通信を行います。しかしながら開発段階では、サーバの正式な証明書は用意されていません(正式なサーバ名も決まるのは、開発の最後の段階だったり、開発が終わってからだったりしますしね)。従って開発段階では、テストサーバを立てて開発を行います。テストサーバとhttps通信を行うとき、もちろんサーバー証明書が必要になりますが、パブリックCA局にお願いしてお金を払ってテストサーバ用サーバ証明書を作成するといった事にはなりません。普通自己証明書(通称オレオレ証明書)を自分で作成してサーバーに配置します。
しかしながら、クライアントから、自己証明書を持つテストサーバにアクセスした場合、正しい署名ではないということでエラーになります。この時このエラーを回避して、「とりあえず」動かすコードを書いてしまいます。
さて、開発は進み、正式なサーバーが用意されましたので、アクセス先のURLを書き換えます。このとき上記の署名のエラーを回避するコードがそのままですと、「SSLサーバ証明書検証不備」の脆弱性を持ったアプリが生み出されます。このような仕組みで、中間者攻撃が可能なアプリが大量に生産されています。
本当にたくさんのアプリが該当します。開発者の方は、一度チェックしてください
脆弱性を生み出さない仕組
話が長くなりましたが、セキュリティの世界では有名なこの話も、なかなか開発者には届きません。
またリリースコードでは削除しなければいけないと思っても削除し忘れという事も良くあります。
この脆弱性を生み出さないようにする仕組みが、Android Nで導入された、「NetWork Secutiry Config」に入っております。Network Security Config機能には、他にも機能が入っておりますが、デバック時のみ用意したCAを使うConfigring CAs for Debuggingという機能はHTTPS通信をする開発者の方にとっては知ってもらいたい機能となります。
まだ、最初のPreview版ですし、色々と今後変更はありますので、あまり深い検証はせずに、翻訳、解説していきたいと思います。
Network Security Configuration(超訳)
今回新しくできた、Network Security Configurationページの翻訳というか超訳です。
AndroidNはネットワークセキュリティ設定(Network Security Configuration)機能が含まれています。この機能はアプリケーションのコードを変更することなく、宣言型設定ファイルを使用してネットワークセキュリティの設定をカスタマイズすることができます。
この設定は、特定のアプリケーションの特定のドメイン設定を変更できます。
この機能の主要な機能は以下となります。
Custom trust anchors:
アプリケーションのセキュア接続にどのCAを信用するかカスタマイズできます。
例えば特定の自己署名証明書を信頼する、制限されたパブリックCAのセットを信用するといった事ができます。
Debug-only overrides:
インストールベースに追加されるリスクなしで、デバッグ時のサーバーとの安全な接続を実現します。
Cleartext trafiic opt-out:
アプリケーションがクリアテキストトラフィックを使用してしまう事故から保護します。
Certificate pining
アプリケーションの特定な証明書へのセキュアなアクセスを実現します。
Adding a Security Configuration File
ネットワークセキュリティコンフィグレーション機能は、アプリケーションの設定をXMLファイルに記載して使用します。そして、アプリケーションのマニュフェストファイルに、このファイルを示すエントリを記載します。
以下のマニュフェストのコードは、このエントリを作成する方法を示しています。
<?xml version="1.0" encoding="utf-8"?> ...<app ...> <meta-data android:name="android.security.net.config" android:resource="@xml/network_security_config" /> ...</app>
補足)nexwork_security_configというネットワーク接続設定用の設定ファイルを作成し、AndoroidManifestに場所を記載する。
アプリは、プラットフォームデフォルトのCA(認証局)の代わりに、CAのカスタムセットを信頼したいことがあります。
これの一般的な理由は以下の通りです。
デフォルトで、すべてのアプリケーションのセキュアコネクション(例:TLS,HTTPS)は、プレインストールされたシステムのCAを信頼します。またtarget API level23(Android M)以下では、デフォルト機能でユーザが追加したCAも信用します。(訳注:端末設定から、信頼できるCA証明書のインストールができる。そしてAndroid Nからはこの機能がなくなった。)
アプリケーションは、自分自身のコネクションについて、base-config(アプリ全体のカスタマイズ用)もしくはdomain-config(ドメイン毎のカスタマイズ用)を使用してカスタマイズ可能です。
Customizing Trusted CAs
アプリは、プラットフォームデフォルトのCA(認証局)の代わりに、CAのカスタムセットを信頼したいことがあります。
これの一般的な理由は以下の通りです。
- カスタム認証局(企業内部CAを使用している等)を使用しているホストに接続する時
- プレインストールされているすべてのCAを信用する代わり、信頼したいCAのセットだけに制限したい時
- システムに含まれていない、信用するCAを追加したい時
デフォルトで、すべてのアプリケーションのセキュアコネクション(例:TLS,HTTPS)は、プレインストールされたシステムのCAを信頼します。またtarget API level23(Android M)以下では、デフォルト機能でユーザが追加したCAも信用します。(訳注:端末設定から、信頼できるCA証明書のインストールができる。そしてAndroid Nからはこの機能がなくなった。)
アプリケーションは、自分自身のコネクションについて、base-config(アプリ全体のカスタマイズ用)もしくはdomain-config(ドメイン毎のカスタマイズ用)を使用してカスタマイズ可能です。
Configuring a Custom CA
自己署名証明書(オレオレ証明書)を使用しているサーバに接続したり、信用する非公開CA(会社の内部CA等)を使用する時に利用できます。
補足:そんなにないですが、端末自体に自己署名ルート証明書を入れるようなアプリケーションが現在ありますが、アプリケーション内に含める事ができるようになったので、運用が楽になりました。
res/xml/network_security_config.xml
:<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">example.com</domain> <trust-anchors> <certificates src="@raw/my_ca"/> </trust-anchors> </domain-config> </network-security-config>
PEMかDERフォーマットのCAの証明書をres/raw/my_caファイル記載します。
Limiting the Set of Trusted CAs
システムにインストールされているCAを信用したくないときに、代わりに指定したCAセットを指定することができます。これは、他のCAによって発行された不正な証明書からアプリを保護します。
信頼できるCAのセットを制限するための設定は、複数のCAがリソースに提供されている以外は、特定のドメインのカスタムCAを信頼することと似ています。
res/xml/network_security_config.xml
:<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">secure.example.com</domain> <domain includeSubdomains="true">cdn.example.com</domain> <trust-anchors> <certificates src="@raw/trusted_roots"/> </trust-anchors> </domain-config> </network-security-config>
信頼するCAはPEMかDERのフォーマットでres/raw/trusted_rootsに追加する。もしPEMフォーマットを使うなら、PEMデータのみを含めなければならずextra textは含めない。また複数行の<certificates>属性を使用することができる。
補足)アンドロイドが普及するに従って、法律が異なる様々な国で使われるようになりました。端末にプリセットされるCAが不正なCAである可能性もありますし、既存の信頼されているCAがおかしな事をする可能性も捨てきれませんので(実際事故は起こっている)非常にセンシティブなアプリケーションの場合はこのような対処が必要になるという事でしょう。特定のサーバーにしか接続しないアプリはこのような仕組みを利用するのもありかもしれません。
参考
Trusting Additional CAs
アプリケーションは、システムによって信頼されていないCAを追加することができる。
これはシステムまだCAを含めていないといった時や、アンドロイドシステムの要件にまだ含まれていなという原因である可能性があります。
これはシステムまだCAを含めていないといった時や、アンドロイドシステムの要件にまだ含まれていなという原因である可能性があります。
アプリは複数の証明書の場所を指定することによりこれを解決できます。
res/xml/network_security_config.xml
:<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config> <trust-anchors> <certificates src="@raw/extracas"/> <certificates src="system"/> </trust-anchors> </base-config> </network-security-config>
Configuring CAs for Debugging
HTTPSで接続するアプリケーションをデバックする時に、本番サーバーのSSL証明書を持っていないローカルの開発サーバに接続することができるようになりました。
アプリケーションのコードを変更することなしに実現するため、デバック時のみ使用するCAを指定することができます。
android:debuggableがtrueの時のみ、debug-overridesに書かれた内容が信用される。
通常、IDEやビルドツールが自動的にリリース版ではないフラグ(android:debuggable)をセットします。
アプリケーションストアは、debuggableのフラグが付いたコードを受け付けないので、これは通常の条件付きのコードよりも安全です。(訳注:グーグルプレイにアップロードできない)
res/xml/network_security_config.xml
:<?xml version="1.0" encoding="utf-8"?> <network-security-config> <debug-overrides> <trust-anchors> <certificates src="@raw/debug_cas"/> </trust-anchors> </debug-overrides> </network-security-config>
Opting Out of Cleartext Traffic
接続先にセキュアな接続のみを使用したいアプリケーションはcleatext(平文)をオプトアプトすることができます。(HTTPSの代わりに暗号化されていないHTTPプロトコルを使用してしまった時)
このオプションは、バックエンドサーバなどの外部リソースから提供されたURLの変更が会った時などの偶発的な問題を防ぐことができます。
詳細については、NetworkSecurityPolicy.isCleartextTrafficPermitted()を参照してください。
例えば、以下の設定ではsecure.example.comへのすべての接続は、常にHTTPSを介して行われていることを確保することができます。
res/xml/network_security_config.xml
:<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config usesCleartextTraffic="false"> <domain includeSubdomains="true">secure.example.com</domain> </domain-config> </network-security-config>
Pinning Certificates
一般的にアプリケーションは全てのプレインストールされているルートCA証明書を信用します。
これらのルート証明書のいずれかが、不正な証明書を発行した場合、アプリケーションはMiTM(中間者攻撃)の危険があります。いくつかのアプリは、信頼するCAのセットを使用したり(訳注:AndroidNで新機能として追加)、証明書のピンニングのいずれかによって、受け入れる証明書セットを制限します。
証明書のピンニングは、公開鍵(X509証明書のSubjectPublicKeyInfo)のハッシュ値のセットを提供することで実現します。
証明書チェインのどれか一つピンニングされた公開鍵が含まれていれば有効です。証明書のピンニングを使う時バックアップキーも含むべきであることに注意してください。新しいキーに切り替える必要があるときや、CA(ルート署名、中間署名をピンニングする時)を変更する時にアプリの接続が影響を受けないようにします。そうしないと、接続を回復するために、アプリを更新する必要があります。
さらに、ピンニング有効期限を設定することができます。
これは、更新されていないアプリケーションでの接続上の問題を防ぐのに役立ちます。
しかし、ピンに有効期限を設定すると、ピンニングのバイパスを可能にすることができます。
res/xml/network_security_config.xml
:<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">example.com</domain> <pin-set expiration="2018-01-01"> <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin> <!-- backup pin --> <pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin> </domain-config> </network-security-config>
- トルコの認証局、中間CA証明書を誤発行--グーグルやMS、対応を明らかに
- Certificate and Public Key Pinning
- 不正なSSL証明書を見破るPublic Key Pinningを試す
Configuration Inheritance Behavior
値をセットしない特定の設定値は継承されます。
これは人間に理解可能な形で、複雑な設定を可能にします。
特定のエントリに値が設定されていない場合、次による一般的なエントリの値が使用されます。
値のセットされていないdomain-configは親のdomain-configの値を継承します。
値のセットされていないbase-configはプラットフォームのデフォルト値を使います。
例えば、example.comのサブドメインへの総ての接続がカスタムセットCAを使用しなければいけないときを検討します。追加で、クリアテキストトラフィックは、serure.example.comに接続している場合を除いて許可されています
ネスティングコンフィグレーションにより、example.comの内部設定のsecure.example.comにはtrust-anchorsを重複して記載する必要はありません(訳注:下記XML参照)
res/xml/network_security_config.xml
:<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config> <domain includeSubdomains="true">example.com</domain> <trust-anchors> <certificates src="@raw/my_ca"/> </trust-anchors> <domain-config cleartextTrafficPermitted="false"> <domain includeSubdomains="true">secure.example.com</domain> </domain-config> </domain-config> </network-security-config>
Configuration File Format
XMLの記載方法の説明なので省略(ざっと見ればわかります)
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config> <trust-anchors> <certificates src="..."/> ... </trust-anchors> </base-config> <domain-config> <domain>android.com</domain> ... <trust-anchors> <certificates src="..."/> ... </trust-anchors> <pin-set> <pin digest="...">...</pin> ... </pin-set> </domain-config> ... <debug-overrides> <trust-anchors> <certificates src="..."/> ... </trust-anchors> </debug-overrides> </network-security-config>
最後に
ネットワークセキュリティ設定機能をまとめますと
- ルート証明書が無条件で信用できなくなった→アプリ単位のCAカスタマイズ
- SSL証明書の検証不備→デバック用CAを使用可能
- CA局信用できないなー→Pinning
- クリアテキスト→んーなんか事件あったっけ?おまけ?
的な感じです。分かりやすいように、問題があった事件のURLも記載してみました。
デバック用のルート証明書って、リリースビルドの時に自動的に消されるのかなぁ、残ってしまうとやだなーとか、ちょと文章だけでは詳細わからない所がありますが、その点は追々調査していきたいと思います。