Weitere ähnliche Inhalte
Ähnlich wie デブサミ2015 事例から学ぶAndroidアプリのセキュアコーディング「SSL/TLS証明書検証の現状と対策」 (20)
Mehr von JPCERT Coordination Center (8)
デブサミ2015 事例から学ぶAndroidアプリのセキュアコーディング「SSL/TLS証明書検証の現状と対策」
- 2. Copyright©2015 JPCERT/CC All rights reserved.
自己紹介
1
熊谷 裕志 (くまがい ひろし)
—情報流通対策グループ 解析チーム リードアナリスト
—2011年4月からJPCERT/CCで脆弱性情報の分析やセキュ
アコーディングの普及活動に携わる
- 3. Copyright©2015 JPCERT/CC All rights reserved.
目次
話題になったニュース
現状
—約5000件のアプリを簡易調査
—アプリをピックアップしてその実装を見てみる
対策方法
—修正されたアプリの実装を見てみる
アプリの解析
—ツール紹介
—デモ
参考情報
2
- 5. 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
- 6. 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
- 8. Copyright©2015 JPCERT/CC All rights reserved.
調査内容
日本のGooglePlayで公開されている5307件のアプリを簡
易調査
—2015/01/27時点
—次のカテゴリの無料トップからアプリをピックアップ
ビジネス、通信、ファイナンス、健康&フィットネス、ライ
フスタイル、医療、仕事効率化、ショッピング、ソーシャル
ネットワーク、ツール、交通
7
- 9. 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)
- 11. Copyright©2015 JPCERT/CC All rights reserved.
調査結果
1930件のアプリに証明書検証不備の可能性
—ただし、あくまで簡易調査
証明書検証を無効にしているコードを含んでいるという意味
全てのアプリでこのコードが生きているかどうかは現時点で
未調査
10
- 13. 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;
}
}
- 14. Copyright©2015 JPCERT/CC All rights reserved.
アプリその2:実装その2
SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIE
Rを使用して、どんなホスト名でも受け付けるようにし
ている
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));
- 15. 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;
}
}
- 16. Copyright©2015 JPCERT/CC All rights reserved.
アプリその4:実装その2
これも先ほどのアプリと同様に
SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIE
Rを使用してどんなホスト名でも受け付けるようにして
いる
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));
- 17. 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();
}
});
- 22. 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
- 23. 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:修正前のコード
- 24. 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();
- 25. Copyright©2015 JPCERT/CC All rights reserved.
修正済みアプリ その2
某ファイナンス系アプリB
https://play.google.com/store/apps/details?id=xx.xxx.xxxx.xxxxx
すでに修正済み
24
- 26. 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);
}
- 27. 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);
- 28. 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];
}
}
- 29. 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);
}
- 30. Copyright©2015 JPCERT/CC All rights reserved.
まとめ
SSL/TLSサーバ証明書の検証はバイパスしない
デバッグのためなら、リリース時は元に戻す
不用意にサンプルをコピペしない
—Exceptionは無視しない
—TrustManagerやHostnameVerifierを独自実装するなら不用
意なバイバスはしない
29
- 32. Copyright©2015 JPCERT/CC All rights reserved.
ツール紹介:mitmproxy
mitmproxy
—http://mitmproxy.org/
インストール方法は
—Windows環境の場合、別途Pythonが必要
https://www.python.org/
31
pip install mitmproxy
- 33. 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
- 34. Copyright©2015 JPCERT/CC All rights reserved.
ツール紹介:apktool
apktool
—https://code.google.com/p/android-apktool/
—apkファイルを解析するためのツール
—機能
リソースファイルのデコード
apkファイルの再構築
その他…
33
- 37. 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
- 39. Copyright©2015 JPCERT/CC All rights reserved.
大事なことなので、もう一度
約36%のアプリに問題がある可能性
SSL/TLSサーバ証明書の検証はバイパスしない
デバッグのためなら、リリース時は元に戻す
不用意にサンプルをコピペしない
—Exceptionは無視しない
—TrustManagerやHostnameVerifierを独自実装するなら不用
意なバイバスはしない
38
- 41. 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