デブサミ2015...

41
事例から学ぶAndroidアプリのセ キュアコーディング「SSL/TLS明書検証の現状と対策」 JPCERT/CC 情報流通対策グループ 脆弱性解析チーム 熊谷 裕志 ([email protected])

Upload: jpcert-coordination-center

Post on 18-Jul-2015

1.181 views

Category:

Software


7 download

TRANSCRIPT

事例から学ぶAndroidアプリのセキュアコーディング「SSL/TLS証明書検証の現状と対策」

JPCERT/CC 情報流通対策グループ 脆弱性解析チーム 熊谷 裕志 ([email protected])

Copyright©2015 JPCERT/CC All rights reserved.

自己紹介

1

熊谷 裕志 (くまがい ひろし) —情報流通対策グループ 解析チーム リードアナリスト

—2011年4月からJPCERT/CCで脆弱性情報の分析やセキュアコーディングの普及活動に携わる

Copyright©2015 JPCERT/CC All rights reserved.

目次

話題になったニュース 現状 —約5000件のアプリを簡易調査 —アプリをピックアップしてその実装を見てみる 対策方法 —修正されたアプリの実装を見てみる アプリの解析 —ツール紹介 —デモ 参考情報

2

Copyright©2015 JPCERT/CC All rights reserved.

2014年 SSL/TLSサーバ証明書検証不備の話題

3

Copyright©2015 JPCERT/CC All rights reserved.

9月 CERT/CC Androidアプリの脆弱性を調査公表

4

多くのAndroidアプリではSSL/TLSサーバ証明書を適切に検証していないことがわかった —https://www.cert.org/blogs/certcc/post.cfm?EntryID=204

検証したアプリのリストが公開されており、現在も更新されている —https://docs.google.com/spreadsheets/d/1t5GXwjw82Syun

ALVJb2w0zi3FoLRIkfGPc7AMjRF0r4/edit?usp=sharing

Copyright©2015 JPCERT/CC All rights reserved.

1月から12月までの間 国内では9件の脆弱性情報が公開

2014/10/23 JVN#27388160: — Android 版 「スマ保」における SSL/TLS サーバ証明書の検証不備の脆弱性

2014/09/25 JVN#48270605: — Yahoo!ボックス(Android版) における SSL サーバ証明書の検証不備の脆弱性

2014/09/22 JVN#04560253: — Android 版アプリ「ゆこゆこ」における SSL サーバ証明書の検証不備の脆弱性

2014/08/29 JVN#17637243: — Android 版アプリ Kindle における SSL サーバ証明書の検証不備の脆弱性

2014/08/14 JVN#27702217: — Android 版 Ameba における SSL サーバ証明書の検証不備の脆弱性

2014/07/30 JVN#72950786: — Android 版 Outlook.com における SSL サーバ証明書の検証不備の脆弱性

2014/06/18 JVN#10603428: — Android 版アプリ「JR東日本アプリ」における SSL サーバ証明書の検証不備の脆弱性

2014/03/17 JVN#16263849: — Android 版アプリ「出前館」における SSL サーバ証明書の検証不備の脆弱性

2014/02/26 JVN#48810179: — Android 版アプリ「デニーズ」における SSL サーバ証明書の検証不備の脆弱性

5

Copyright©2015 JPCERT/CC All rights reserved.

現状

6

Copyright©2015 JPCERT/CC All rights reserved.

調査内容 日本のGooglePlayで公開されている5307件のアプリを簡易調査

—2015/01/27時点 —次のカテゴリの無料トップからアプリをピックアップ

ビジネス、通信、ファイナンス、健康&フィットネス、ライフスタイル、医療、仕事効率化、ショッピング、ソーシャルネットワーク、ツール、交通

7

Copyright©2015 JPCERT/CC All rights reserved.

調査内容 証明書検証の実装に問題がある可能性の判断

—X509TrustManagerをチェック

checkServerTrustedメソッド等を空にしているか —HostnameVerifierをチェック

verifyメソッドを常にtrueにしているか —ALLOW_ALL_HOSTNAME_VERIFIERをチェック

8

JSSEC セキュアコーディングガイド 5.4.3.3. 証明書検証を無効化する危険なコード (https://www.jssec.org/dl/android_securecoding.pdf)

Copyright©2015 JPCERT/CC All rights reserved. 9

危険なコード例

Copyright©2015 JPCERT/CC All rights reserved.

調査結果 1930件のアプリに証明書検証不備の可能性 —ただし、あくまで簡易調査

証明書検証を無効にしているコードを含んでいるという意味 全てのアプリでこのコードが生きているかどうかは現時点で未調査

10

Copyright©2015 JPCERT/CC All rights reserved.

カテゴリ別割合

11

0% 10% 20% 30% 40% 50% 60% 70% 80% 90%

100%

各カテゴリにおける問題のコードを含むアプリの割合

Copyright©2015 JPCERT/CC All rights reserved.

アプリその1:実装その1 独自実装のTrustManagerを使用している

12

package xxxx.xxxx.xxxx.xxxx.xxxx.xxxx; import java.security.cert.X509Certificate; import javax.net.ssl.X509TrustManager; class g implements X509TrustManager { g(f arg1) { this.a = arg1; super(); } public void checkClientTrusted(X509Certificate[] arg1, String arg2) { } public void checkServerTrusted(X509Certificate[] arg1, String arg2) { } public X509Certificate[] getAcceptedIssuers() { return null; } }

Copyright©2015 JPCERT/CC All rights reserved.

アプリその2:実装その2

SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIERを使用して、どんなホスト名でも受け付けるようにしている

13

h.a = new HttpPost(v0); h.a.setHeader("Content-Type", "image/jpeg"); h.a.setHeader("Accept-Language", "ja-jp"); h.a.setHeader("Accept-Encoding", "gzip, deflate"); h.a.setHeader("Proxy-Connection", "keep-alive"); h.a.setHeader("User-Agent", v1); KeyStore v0_1 = KeyStore.getInstance(KeyStore.getDefaultType()); v0_1.load(v2, ((char[])v2)); f v1_1 = new f(v0_1); ((SSLSocketFactory)v1_1).setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); SchemeRegistry v0_2 = new SchemeRegistry(); v0_2.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); v0_2.register(new Scheme("https", ((SocketFactory)v1_1), 443));

Copyright©2015 JPCERT/CC All rights reserved.

アプリその3:実装その1 このアプリも先ほど同様、独自実装のTrustManagerを使用している

14

package xxxx.xxxx.xxxx.xxxx.xxxx; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.X509TrustManager; class xxxx.xxxx.xxxx.xxxx.xxxx.MySSLSocketFactory$1 implements X509TrustManager { xxxx.xxxx.xxxx.xxxx.xxxx.MySSLSocketFactory$1(MySSLSocketFactory arg1) { MySSLSocketFactory.this = arg1; super(); } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }

Copyright©2015 JPCERT/CC All rights reserved.

アプリその4:実装その2

これも先ほどのアプリと同様にSSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIERを使用してどんなホスト名でも受け付けるようにしている

15

public HttpClient(StringBuilder _sb) throws Exception { super(); this.httpClient = new DefaultHttpClient(); this.httpContext = new BasicHttpContext(); this.stringBuilder = _sb; KeyStore v2 = KeyStore.getInstance(KeyStore.getDefaultType()); v2.load(null, null); MySSLSocketFactory v1 = new MySSLSocketFactory(v2); ((SSLSocketFactory)v1).setHostnameVerifier( SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); this.httpClient.getConnectionManager().getSchemeRegistry().register( new Scheme("https", ((SocketFactory) v1), 443));

Copyright©2015 JPCERT/CC All rights reserved.

その他

WebViewにおいて、SSL通信のエラーを無視してそのまま処理を実行するようにしている

16

mWebView.setWebViewClient(new WebViewClient() { @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { handler.proceed(); } });

Copyright©2015 JPCERT/CC All rights reserved.

なぜ?

17

Copyright©2015 JPCERT/CC All rights reserved.

SSL/TLSサーバ証明書の検証をしていないと

中間者攻撃によって、HTTPS通信の内容を盗聴や改ざんされてしまう

18

Copyright©2015 JPCERT/CC All rights reserved.

対策方法は?

19

Copyright©2015 JPCERT/CC All rights reserved. 20

Copyright©2015 JPCERT/CC All rights reserved.

修正済みアプリ その1 某ファイナンス系アプリA —https://play.google.com/store/apps/details?id=xxx.xxxxx.xx

xxxxx.xxxxxx すでに修正済み 古いバージョンではSSL/TLSサーバ証明書を検証していなかった

21

Copyright©2015 JPCERT/CC All rights reserved. 22

xxx.xxxx.xxxxx.xxxx.ApiRequest$1 v12 = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; try { SSLContext v18 = SSLContext.getInstance("TLS"); v18.init(null, new TrustManager[]{v12}, null); ((HttpsURLConnection)v8).setSSLSocketFactory(v18.getSocketFactory()); ((HttpsURLConnection)v8).setSSLSocketFactory(v18.getSocketFactory()); ((HttpsURLConnection)v8).setHostnameVerifier(new HostnameVerifier() { public boolean verify(String string, SSLSession ssls) { return 1; } }); ((HttpURLConnection)v8).setRequestMethod("POST"); ((HttpURLConnection)v8).setDoOutput(true); ((HttpURLConnection)v8).setRequestProperty("Referer", ”xxx.xxx.xxxx.xxx"); ((HttpURLConnection)v8).setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); ((HttpURLConnection)v8).setRequestProperty("Content-Length", v16.length()); ((HttpURLConnection)v8).setRequestProperty("User-Agent", this.mUserAgent); ((HttpURLConnection)v8).setRequestProperty("X-Requested-With", "xmlHttpRequest"); ((HttpURLConnection)v8).setInstanceFollowRedirects(false); ((HttpURLConnection)v8).connect();

修正済みアプリ その1:修正前のコード

Copyright©2015 JPCERT/CC All rights reserved.

修正済みアプリ その1:修正後のコード

独自実装のTrustManagerやHostnameVerifierがなくなっている

23

try { URL v14 = new URL(url.split("¥¥?")[0]); String v12 = new URL(url).getQuery(); v5 = v14.openConnection(); ((HttpURLConnection)v5).setRequestMethod("POST"); ((HttpURLConnection)v5).setDoOutput(true); ((HttpURLConnection)v5).setRequestProperty("Referer", ”xxx.xxx.xxxx.xxx"); ((HttpURLConnection)v5).setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); ((HttpURLConnection)v5).setRequestProperty("Content-Length", v12.length()); ((HttpURLConnection)v5).setRequestProperty("User-Agent", this.mUserAgent); ((HttpURLConnection)v5).setRequestProperty("X-Requested-With", "xmlHttpRequest"); ((HttpURLConnection)v5).setInstanceFollowRedirects(false); ((HttpURLConnection)v5).connect();

Copyright©2015 JPCERT/CC All rights reserved.

修正済みアプリ その2 某ファイナンス系アプリB

https://play.google.com/store/apps/details?id=xx.xxx.xxxx.xxxxx すでに修正済み

24

Copyright©2015 JPCERT/CC All rights reserved.

修正済みアプリ その2:修正前のコード 1/3

SSLSocketFactoryを呼び出している

25

public class a extends b { public a(Context arg1, h arg2, URI arg3, List arg4) { super(arg1, arg2, arg3, arg4); } protected Void a(Void[] arg9) { HttpResponse v1; Void v2 = null; HttpPost v0 = new HttpPost(this.b); HttpClient v3 = k.a(); try { if(this.h > 0) { v0.getParams().setIntParameter("http.connection.timeout", this.h); v0.getParams().setIntParameter("http.socket.timeout", this.h); }

Copyright©2015 JPCERT/CC All rights reserved.

修正済みアプリ その2:修正前のコード 2/3

SSLSocketFactoryを継承して独自のTrustManagerを使用している

26

public class k { class a extends SSLSocketFactory { private SSLContext a; public a(KeyStore arg6) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(arg6); this.a = SSLContext.getInstance("TLS"); this.a.init(null, new TrustManager[]{new l(this)}, null);

Copyright©2015 JPCERT/CC All rights reserved.

修正済みアプリ その2:修正前のコード 3/3

独自実装のTrustManagerを実装している

27

class l implements X509TrustManager { l(a arg1) { this.a = arg1; super(); } public void checkClientTrusted(X509Certificate[] arg1, String arg2) throws CertificateException { } public void checkServerTrusted(X509Certificate[] arg1, String arg2) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } }

Copyright©2015 JPCERT/CC All rights reserved.

修正済みアプリ その2:修正後のコード

独自実装のTrustManagerは使用しなくなっている

28

private Void c() { HttpResponse v2_1; HttpResponse v1; Void v2 = null; HttpPost v0 = new HttpPost(this.b); DefaultHttpClient v3 = new DefaultHttpClient(); try { if(this.h > 0) { v0.getParams().setIntParameter("http.connection.timeout", this.h); v0.getParams().setIntParameter("http.socket.timeout", this.h); }

Copyright©2015 JPCERT/CC All rights reserved.

まとめ SSL/TLSサーバ証明書の検証はバイパスしない デバッグのためなら、リリース時は元に戻す 不用意にサンプルをコピペしない —Exceptionは無視しない —TrustManagerやHostnameVerifierを独自実装するなら不用意なバイバスはしない

29

Copyright©2015 JPCERT/CC All rights reserved.

アプリの解析方法

30

Copyright©2015 JPCERT/CC All rights reserved.

ツール紹介:mitmproxy mitmproxy —http://mitmproxy.org/

インストール方法は —Windows環境の場合、別途Pythonが必要

https://www.python.org/

31

pip install mitmproxy

Copyright©2015 JPCERT/CC All rights reserved.

ツール紹介:Fiddler Fiddler —http://www.telerik.com/fiddler

Androidアプリの通信をキャプチャするために設定を変更する —[Tools] > [Fiddler Options]

[HTTPS] > [Decrypt HTTPS traffic] [Connections] > [Allow remote computers to connect]

32

Copyright©2015 JPCERT/CC All rights reserved.

ツール紹介:apktool apktool —https://code.google.com/p/android-apktool/ —apkファイルを解析するためのツール

—機能

リソースファイルのデコード apkファイルの再構築 その他…

33

Copyright©2015 JPCERT/CC All rights reserved.

ツール紹介:dex2jar dex2jar —https://code.google.com/p/dex2jar/ —DEXファイルをJavaクラスファイルに変換するツール

34

Copyright©2015 JPCERT/CC All rights reserved.

ツール紹介:JD-GUI JD-GUI —http://jd.benow.ca/ —Javaクラスファイルをデコンパイルするツール

35

Copyright©2015 JPCERT/CC All rights reserved.

MalloDroid AndroidアプリのSSL/TLSサーバ証明書検証の実装に問題があるかどうかチェックしてくれるツール —https://github.com/sfahl/mallodroid

必要なもの —androguard

https://github.com/androguard/androguard インストールに必要なもの

—https://code.google.com/p/androguard/wiki/Installation

36

Copyright©2015 JPCERT/CC All rights reserved.

DEMO

37

Copyright©2015 JPCERT/CC All rights reserved.

大事なことなので、もう一度 約36%のアプリに問題がある可能性 SSL/TLSサーバ証明書の検証はバイパスしない デバッグのためなら、リリース時は元に戻す 不用意にサンプルをコピペしない —Exceptionは無視しない —TrustManagerやHostnameVerifierを独自実装するなら不用意なバイバスはしない

38

Copyright©2015 JPCERT/CC All rights reserved.

参考情報

39

Copyright©2015 JPCERT/CC All rights reserved.

Androidアプリのセキュア設計・セキュアコーディングガイド —https://www.jssec.org/report/securecoding.html

Android Pinning by Moxie Marlinspike —https://github.com/moxie0/AndroidPinning

Finding Android SSL Vulnerabilities with CERT Tapioca —https://www.cert.org/blogs/certcc/post.cfm?EntryID=204

Android apps that fail to validate SSL —https://docs.google.com/spreadsheets/d/1t5GXwjw82Syun

ALVJb2w0zi3FoLRIkfGPc7AMjRF0r4/edit?usp=sharing

40