├── AddJavascriptInterface.md ├── AllowAllHostnameVerifier.md ├── AllowBackup.md ├── AuthLeak.md ├── BadHostnameVerifier.md ├── EasterEgg.md ├── ExportedContentProvider.md ├── ExportedPreferenceActivity.md ├── ExportedReceiver.md ├── ExportedService.md ├── GetInstance.md ├── GrantAllUris.md ├── HardcodedDebugMode.md ├── HardwareIds.md ├── InvalidPermission.md ├── JavascriptInterface.md ├── PackageManagerGetSignatures.md ├── PackagedPrivateKey.md ├── SSLCertificateSocketFactoryCreateSocket.md ├── SSLCertificateSocketFactoryGetInsecure.md ├── SecureRandom.md ├── SetJavascriptEnabled.md ├── SetWorldReadable.md ├── SetWorldWritable.md ├── SignatureOrSystemPermissions.md ├── TrulyRandom.md ├── TrustAllX509TrustManager.md ├── UnprotectedSMSBroadcastReceiver.md ├── UnsafeDynamicallyLoadedCode.md ├── UnsafeNativeCodeLocation.md ├── UnsafeProtectedBroadcastReceiver.md ├── UseCheckPermission.md ├── UsingHttp.md ├── VulnerableColdovaVersion.md ├── VulnerableCordovaVersion.md ├── WorldReadableFiles.md ├── WorldWritableFiles.md ├── WrongConstant.md ├── config.json ├── index.html ├── index.md ├── myStyles.css └── navigation.md /AddJavascriptInterface.md: -------------------------------------------------------------------------------- 1 | # addJavascriptInterface Called (AddJavascriptInterface) 2 | 3 | ## 警告されている問題点 4 | 5 | WebViewの脆弱性をついた攻撃により、アプリ機能の不正利用や、情報漏洩・改竄のリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | AddJavascriptInterfaceを使用する際は、以下のいずれかの対策を実施してください。 10 | 11 | - アプリがサポートするバージョンを脆弱性のないものに設定する 12 | - WebViewがロードするリソースを信頼できるものに限定する 13 | 14 | ## 対策の具体例 15 | 16 | ### サポートするAndroidバージョンを脆弱性のないものに設定する 17 | 18 | [CVE-2012-6636][3]、[CVE-2013-4710][4]、および[CVE-2014-7224][7]の致命的な脆弱性がAndroid 4.2(API 17)で修正されたので、これ以前のバージョンをサポートすべき合理的な理由がない場合には、minSdkVersionを17以上に設定してください。 19 | Android 4.2からは、Javaコード上にJavascriptInterfaceアノテーションのないメソッドにはJavaScriptからアクセスできなくなったため、リフレクション[^注釈1]により任意のコードを実行されるリスクがなくなります。 20 | 21 | サポートする最小バージョン(minSdkVersion)の変更は、Android Studioで以下のように行います。 22 | 23 | ``` 24 | 1. Tools -> Android -> Android SDK Default Setting 画面でSDKインストール 25 | (指定するバージョンがインストール済なら1.の作業は不要) 26 | 2. File -> Project Structure… 画面から、アプリのFlavorsタグのMin Sdk Versionを変更 27 | ``` 28 | 29 | ### ロードするリソースを信頼できるものに限定する 30 | 31 | 不正なJavaScriptを含まない信頼できるリソースのみを読み込むようにしてください。読み込むリソースを自社の管理の及ぶ範囲や、Google社など信頼できる第三者が提供するもののみにすることで、攻撃されるリスクを抑えられます。 32 | 33 | ```java 34 | public class ActivitySample extends Activity { 35 | // JavaScript実行用クラス 36 | class CallFromJavaScript { 37 | @JavascriptInterface 38 | public methodA() {...} 39 | 40 | // API 17以降では@JavascriptInterfaceのないメソッドはJavaScriptから実行できない 41 | public methodB() {...} 42 | } 43 | 44 | @Override 45 | protected void onCreate(Bundle savedInstanceState) { 46 | super.onCreate(savedInstanceState); 47 | 48 | WebView webView = new WebView(this); 49 | setContentView(webView); 50 | 51 | // JavaScriptを有効にする 52 | webView.getSettings().setJavaScriptEnabled(true); 53 | 54 | // JavaScriptから呼び出し可能にするJavaオブジェクトを設定する 55 | webView.addJavascriptInterface(new CallFromJavaScript(), "callMe"); 56 | 57 | webView.setWebViewClient(new WebViewClient(){ 58 | @TargetApi(Build.VERSION_CODES.N) 59 | @Override 60 | public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { 61 | // assetsディレクトリ以下以外のファイルには遷移しないようにする 62 | return !request.getUrl().toString().startsWith("file:///android_asset/"); 63 | } 64 | 65 | // 本メソッドはAPI 24で非推奨となった 66 | @Override 67 | public boolean shouldOverrideUrlLoading(WebView view, String url) { 68 | // assetsディレクトリ以下以外のファイルには遷移しないようにする 69 | return !url.startsWith("file:///android_asset/"); 70 | } 71 | } 72 | 73 | // 信頼できるリソースをロードする 74 | webView.loadUrl("file:///android_asset/index.html"); 75 | } 76 | } 77 | ``` 78 | 79 | Android 4.1(API 17)以下のバージョンをサポートする場合は、ロードするリソースの検証が行えないためにLintはメッセージを出力し続けます。 80 | 81 | ## 不適切な例 82 | 83 | 検索結果や広告に紛れている悪意のあるサイトをロードしてしまうケースは少なくありません。 84 | JavaScriptが有効になっている状態で悪意のあるサイトをロードすると、任意のコードを実行されてしまうリスクがあります。 85 | 86 | ```java 87 | public class ActivitySample extends Activity { 88 | class CallFromJavaScript { 89 | @JavascriptInterface 90 | public methodA() {...} 91 | 92 | public methodB() {...} 93 | } 94 | 95 | @Override 96 | protected void onCreate(Bundle savedInstanceState) { 97 | super.onCreate(savedInstanceState); 98 | WebView webView = new WebView(this); 99 | webView.getSettings().setJavaScriptEnabled(true); // JavaScriptを有効にする 100 | 101 | // JavaScriptから呼び出し可能にするJavaオブジェクトを設定する 102 | webView.addJavascriptInterface(new CallFromJavaScript(), "callMe"); 103 | 104 | // 信頼できないリソースにアクセスする 105 | webView.loadUrl(untrustUrl); 106 | 107 | setContentView(webView); 108 | } 109 | } 110 | ``` 111 | 112 | Lintは、minSdkVersionが17未満でaddJavascriptInterface()メソッドの呼び出しを検知すると、次のようなメッセージを出力します。 113 | 114 | - Lint出力(Warning) 115 | “\`WebView.addJavascriptInterface\` should not be called with minSdkVersion < 17 for security reasons: JavaScript can use reflection to manipulate application” 116 | 117 | 注意: Android 4.1(API 16)以下のバージョンでは、開発者がaddJavascriptInterfaceメソッドを使用していない場合でも、フレームワークがデフォルトで呼び出していることがあるため危険です。([CVE-2013-4710][4]、[CVE-2014-7224][7]) 118 | 119 | ## 外部リンク 120 | 121 | - [WebView | Android Developers][1] 122 | - [WebSettings | Android Developers][2] 123 | - [CVE-2012-6636][3] 124 | - [CVE-2013-4710][4] 125 | - [スマートフォンアプリへのブラウザ機能の実装に潜む危険――WebViewクラスの問題について][5] 126 | addJavascriptInterfaceメソッドの使い方によっては脆弱性を作りこんでしまうという指摘(2012年) 127 | - [Two New Attack Vectors to Aggravate the Android addJavascriptInterface RCE Issue (CVE-2014-7224)][7] 128 | addJavascriptInterfaceメソッドの呼び出しをフレームワークが無条件に行う脆弱性についての記載 129 | 130 | [1]:https://developer.android.com/reference/android/webkit/WebView.html 131 | [2]:https://developer.android.com/reference/android/webkit/WebSettings.html 132 | [3]:http://www.cvedetails.com/cve/CVE-2012-6636/ 133 | [4]:http://www.cvedetails.com/cve/CVE-2013-4710/ 134 | [5]:https://codezine.jp/article/detail/6618 135 | [7]:http://daoyuan14.github.io/news/newattackvector.html 136 | 137 | 138 | [^注釈1]: javascript:void(0); "リフレクション:プログラム実行時に、クラス名やメソッド名を動的に指定して実行(アクセス)するJavaの機能" 139 | -------------------------------------------------------------------------------- /AllowAllHostnameVerifier.md: -------------------------------------------------------------------------------- 1 | # Insecure HostnameVerifier (AllowAllHostnameVerifier) 2 | 3 | ## 警告されている問題点 4 | 5 | SSL/TLS証明書のホスト名検証を正しく行っていないため、HTTPS通信などに対する中間者攻撃[^1]を受けるリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - 証明書検証を省略するためにAllowAllHostnameVerifierクラスなどを使用しない 10 | 11 | ## 対策の具体例 12 | 13 | SSL/TLS通信においては、サーバーの証明書検証およびホスト名検証を必ず行うようにしてください。 14 | 具体的には[TrustAllX509TrustManager](TrustAllX509TrustManager.md)の項を参照してください。 15 | 16 | ## 不適切な例 17 | 18 | - org.apache.http.conn.ssl.SSLSocketFactory[^注釈]クラスのsetHostnameVerifierメソッド 19 | - javax.net.ssl.HttpsURLConnectionクラスのsetHostnameVerifierメソッド 20 | 21 | 上記メソッドの引数に以下のものを指定した場合、ホスト名検証が行われないために意図せぬサーバーに接続してしまう可能性があります。 22 | 23 | - org.apache.http.conn.ssl.AllowAllHostnameVerifier[^注釈]クラスのインスタンス 24 | - org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER 25 | 26 | ```java 27 | try { 28 | URL url = new URL("https://www.example.com"); 29 | HttpsURLConnection conn = (HttpsURLConnection)url.openConnection(); 30 | conn.setHostnameVerifier(new AllowAllHostnameVerifier()); // ホスト名検証が行われなくなる 31 | conn.connect(); 32 | : 33 | } catch (IOException e) { 34 | : 35 | } 36 | ``` 37 | 38 | Lintは、AllowAllHostnameVerifierの使用を検知すると、次のようなメッセージを出力します。 39 | 40 | - Lint出力(Warning) 41 | "Using the AllowAllHostnameVerifier HostnameVerifier is unsafe because it always returns true, which could cause insecure network traffic due to trusting TLS/SSL server certificates for wrong hostnames" 42 | 43 | Lintは、ALLOW_ALL_HOSTNAME_VERIFIERの使用を検知すると、次のようなメッセージを出力します。 44 | 45 | - Lint出力(Warning) 46 | "Using the ALLOW_ALL_HOSTNAME_VERIFIER HostnameVerifier is unsafe because it always returns true, which could cause insecure network traffic due to trusting TLS/SSL server certificates for wrong hostnames" 47 | 48 | ## 外部リンク 49 | 50 | - [プレス発表 【注意喚起】HTTPSで通信するAndroidアプリの開発者はSSLサーバー証明書の検証処理の実装を][1] 51 | - [Network Security Configuration | Android Developers][2] 52 | - [Android アプリのセキュア設計・セキュアコーディングガイド][3] 53 | [「5.4.2.4. 独自の TrustManager を作らない(必須)」][4] 54 | [「5.4.3.7. Network Security Configuration」][5] 55 | 56 | 57 | [1]: https://www.ipa.go.jp/about/press/20140919_1.html 58 | [2]: https://developer.android.com/training/articles/security-config.html 59 | [3]: https://www.jssec.org/dl/android_securecoding/ 60 | [4]: https://www.jssec.org/dl/android_securecoding/5_how_to_use_security_functions.html#%E7%8B%AC%E8%87%AA%E3%81%AEtrustmanager%E3%82%92%E4%BD%9C%E3%82%89%E3%81%AA%E3%81%84-%EF%BC%88%E5%BF%85%E9%A0%88%EF%BC%89 61 | [5]: https://www.jssec.org/dl/android_securecoding/5_how_to_use_security_functions.html#network-security-configuration 62 | 63 | [^注釈]: javascript:void(0); "API 22以降deprecated" 64 | [^1]: dummy "中間者攻撃:通信している2人のユーザーの間に第三者が介在し、送信者と受信者の両方になりすまして、ユーザーが気付かないうちに通信を盗聴したり、制御したりすること" -------------------------------------------------------------------------------- /AllowBackup.md: -------------------------------------------------------------------------------- 1 | # AllowBackup/FullBackupContent Problems (AllowBackup) 2 | 3 | ## 警告されている問題点 4 | 5 | アプリデータのバックアップ/リストア許可設定を適切に行っていない可能性があるため、アプリの重要情報の漏洩や改竄のリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | バックアップ/リストアに関して、以下のいずれかの対策を実施してください。 10 | 11 | - 原則、アプリのデータのバックアップ/リストアを不許可とする 12 | - バックアップ対象を公開されても問題ないデータに限定する 13 | 14 | ## 対策の具体例 15 | 16 | ### アプリのデータのバックアップ/リストアを許可しない 17 | 18 | アプリがバックアップを必要とするデータを持たないなら、情報が公開されるリスクを減らすためバックアップ/リストアを不許可に設定してください。 19 | 20 | ``` 21 | 28 | 29 | ``` 30 | 31 | ### バックアップ対象を公開されても問題ないデータに限定する 32 | 33 | バックアップされたファイルは、ユーザーによる自由な読み書きが可能です。 34 | そのため、ユーザーに公開したくない(改竄されたくない)情報はバックアップ対象にしないでください。 35 | 36 | また、別の端末でリストアされた場合を考慮し、デバイスを特定するような識別データは除外する必要があります。 37 | 例えば、Google Cloud Messaging(GCM)の登録IDを別の端末にリストアしてしまうとGCMメッセージを正しく受信しなくなります。 38 | 39 | Android5.1(API22)以前の端末をサポートする場合は、BackupAgentを実装する必要があります。 40 | この実装の詳細に関しては、[Android Devlopers][3]を参照してください。 41 | 実装したBackupAgentを使用するにはマニフェストに以下のように記述します。 42 | 43 | ``` 44 | 52 | ``` 53 | 54 | Android 6.0 (API 23)以降の端末では、[Auto Backup][1]の機能を利用することで、設定ファイル(XML)によりファイルやフォルダ単位の指定を行うことができます。 55 | 56 | ``` 57 | 65 | 66 | ``` 67 | 68 | 上の場合、res/xml/my_backup.xmlファイルにバックアップ対象を記述します。 69 | my_backup.xmlに下のようにincludeで対象、excludeで対象外を指定します。 70 | 設定ファイルの書き方の詳細は、[Android Devlopers][1-3]を参照してください。 71 | 72 | ``` 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | ``` 81 | 82 | バックアップの対象・非対象を判断する際は、[XML Config Syntax | Android Developers][1-2]も参考にしてください。 83 | 84 | Android 5.1以前と6.0以降の端末どちらもサポートする場合は、下のようにfullBackupOnly属性を使用します。 85 | これをtrueに設定することで6.0以降ではBackupAgentを使用せず、fullBackupContent属性に指定した設定が使用されます。 86 | 87 | ``` 88 | 98 | ``` 99 | 100 | ## 不適切な例 101 | 102 | ### バックアップの意思を明確にしていない 103 | 104 | allowBackup属性を指定しない場合、デフォルトでバックアップが許可され、すべてのアプリファイルがバックアップの対象になります。 105 | 106 | ``` 107 | 108 | 114 | ``` 115 | 116 | Lintは、allowBackup属性の指定がないことを検知すると、次のようなメッセージを出力します。 117 | 118 | - Lint出力(Warning) 119 | "Should explicitly set \`android:allowBackup\` to \`true\` or \`false\` (it's \`true\` by default, and that can have some security implications for the application's data)" 120 | 121 | ### バックアップ対象を明確にしていない 122 | 123 | BackupAgentや設定ファイル(XML)でバックアップ対象になるファイルやデータを明示的に指定しなければ、すべてのアプリファイルがバックアップの対象になります。 124 | 125 | ``` 126 | 127 | 134 | ``` 135 | 136 | Lintは、fullBackupContent属性の指定がないことを検知すると、次のようなメッセージを出力します。 137 | 138 | - Lint出力(Warning) 139 | "On SDK version 23 and up, your app data will be automatically backed up, and restored on app install. 140 | Consider adding the attribute \`android:fullBackupContent\` to specify an \`@xml\` resource which configures which files to backup. More info: https://developer.android.com/training/backup/autosyncapi.html" 141 | 142 | 注意: backupAgent属性の有無に関しては検知しません。 143 | 144 | 加えて、マニフェストに[GCM Receiver][4]が定義されていることを検知すると、次のようなメッセージを出力します。 145 | 146 | - Lint出力(Warning) 147 | "On SDK version 23 and up, your app data will be automatically backedup, and restored on app install. Your GCM regid will not work across restores, so you must ensure that it is excluded from the back-up set.Use the attribute \`android:fullBackupContent\` to specify an \`@xml\` resource which configures which files to backup. More info: https://developer.android.com/training/backup/autosyncapi.html" 148 | 149 | fullBackupContent属性の指定があってもファイルが存在しない場合は、次のようなメッセージを出力します。 150 | 151 | - Lint出力(Warning) 152 | "Missing \`<full-backup-content>\` resource" 153 | 154 | ## 外部リンク 155 | 156 | - [Back Up User Data with Auto Backup | Android Devlopers][1] 157 | - [XML Config Syntax | Android Developers][1-2] 158 | - [Including and excluding files | Android Devlopers][1-3] 159 | - [BackupAgent | Android Developers][2] 160 | - [Back Up Key-Value Pairs with Android Backup Service | Android Developers][3] 161 | - [Set up a GCM Client App on Android | Google Developers][4] 162 | 163 | 164 | [1]: https://developer.android.com/guide/topics/data/autobackup.html 165 | [1-2]: https://developer.android.com/guide/topics/data/autobackup.html#XMLSyntax 166 | [1-3]: https://developer.android.com/guide/topics/data/autobackup.html#IncludingFiles 167 | [2]: https://developer.android.com/reference/android/app/backup/BackupAgent.html 168 | [3]: https://developer.android.com/guide/topics/data/keyvaluebackup.html 169 | [4]: https://developers.google.com/cloud-messaging/android/client 170 | -------------------------------------------------------------------------------- /AuthLeak.md: -------------------------------------------------------------------------------- 1 | # Code might contain an auth leak (AuthLeak) 2 | 3 | ## 警告されている問題点 4 | 5 | パスワードがハードコードされているため、なりすましや不正アクセスのリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - Basic認証のパスワードをハードコードしない 10 | 11 | ## 対策の具体例 12 | 13 | Basic認証を行う場合、初回はユーザーにパスワードを入力させてCookieに保存するなどして、パスワードをハードコードしないようにしてください。 14 | 15 | ```java 16 | URL url = new URL("http://www.example.com"); 17 | URLConnection conn = url.openConnection(); 18 | 19 | String password = ""; 20 | for(String cookie : getCookies("www.example.com").split(";")) { 21 | // cookieに保存済みのパスワードがあれば取得する 22 | if(isPassword(cookie)) { 23 | password = parsePassword(cookie); 24 | break; 25 | } 26 | } 27 | 28 | // パスワードをcookieから取得できなかった場合の処理 29 | (省略) 30 | 31 | conn.setRequestProperty("Authorization", "Basic " + 32 | Base64.encodeToString((username + ":" + password).getBytes(), Base64.NO_WRAP)); 33 | InputStream is = conn.getInputStream(); 34 | ``` 35 | 36 | 上のような対策を実施したとしても、重要な処理の認証にBasic認証のみを利用することは避けるのが賢明です。 37 | 38 | ## 不適切な例 39 | 40 | ソースコード中にパスワード付きBasic認証用URLを記載している場合、APKファイルを解析されるとパスワードは簡単に漏洩します。 41 | ソースコード以外の場所へ記載しても、リスクはさほど小さくなりません。 42 | 43 | ```java 44 | String badurl = "http://user1:password1@www.example.com"; 45 | ``` 46 | 47 | Lintは、上の例のように「プロトコル://ユーザ名:パスワード@接続先」形式の文字列を検知すると、次のようなメッセージを出力します。 48 | 49 | - Lint出力(Warning) 50 | "Possible credential leak" 51 | 52 | ただし、リソースファイルなどソースコード以外の場所への記載は検出できません。 53 | 54 | -------------------------------------------------------------------------------- /BadHostnameVerifier.md: -------------------------------------------------------------------------------- 1 | # Insecure HostnameVerifier (BadHostnameVerifier) 2 | 3 | ## 警告されている問題点 4 | 5 | SSL/TLS証明書のホスト名検証を正しく行っていないため、HTTPS通信などに対する中間者攻撃[^1]を受けるリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - 独自のHostnameVerifierを作らない 10 | 11 | ## 対策の具体例 12 | 13 | 独自のHostnameVerifierを安全に実装することは可能ではありますが、暗号処理や暗号通信に十分な知識をもった技術者でなければミスを作り込む危険性があるため、既存の安全な仕組みでサーバーの証明書検証およびホスト名検証を行うようにしてください。 14 | 具体的には[TrustAllX509TrustManager](TrustAllX509TrustManager.md)の項を参照してください。 15 | 16 | ## 不適切な例 17 | 18 | 証明書検証を省略するためにjavax.net.ssl.HostnameVerifierインタフェースのサブクラスでverifyメソッドが常にtrueを返すと、中間者攻撃[^1]を受けるリスクがあります。 19 | 20 | ```java 21 | HostnameVerifier allowAllHV = new HostnameVerifier() { 22 | @Override 23 | public boolean verify(String hostname, SSLSession session) { 24 | return true; // どんなホスト名でも信頼する 25 | } 26 | }; 27 | ``` 28 | 29 | Lintは、HostnameVerifierのverifyメソッドが常にtrueを返す実装であることを検知すると、次のようなメッセージを出力します。 30 | 31 | - Lint出力(Warning) 32 | "\`verify\` always returns \`true\`, which could cause insecure network traffic due to trusting SSL/TLS server certificates for wrong hostnames" 33 | 34 | このチェックは簡易的なもののため、証明書検証の正当性は判断できません。 35 | 独自HostnameVerifierを実装する場合は、証明書検証を適切に行えているかを慎重に確認する必要があります。 36 | 37 | ## 外部リンク 38 | 39 | - [プレス発表 【注意喚起】HTTPSで通信するAndroidアプリの開発者はSSLサーバー証明書の検証処理の実装を][1] 40 | - [HTTPS および SSL によるセキュリティ | Android Developers「ホスト名の確認に関する一般的な問題」][2] 41 | - [Network Security Configuration | Android Developers][3] 42 | - [Android アプリのセキュア設計・セキュアコーディングガイド][4] 43 | [「5.4.2.4. 独自の TrustManager を作らない(必須)」][5] 44 | [「5.4.3.7. Network Security Configuration」][6] 45 | 46 | 47 | [1]: https://www.ipa.go.jp/about/press/20140919_1.html 48 | [2]: https://developer.android.com/training/articles/security-ssl.html#CommonHostnameProbs 49 | [3]: https://developer.android.com/training/articles/security-config.html 50 | [4]: https://www.jssec.org/dl/android_securecoding/ 51 | [5]: https://www.jssec.org/dl/android_securecoding/5_how_to_use_security_functions.html#%E7%8B%AC%E8%87%AA%E3%81%AEtrustmanager%E3%82%92%E4%BD%9C%E3%82%89%E3%81%AA%E3%81%84-%EF%BC%88%E5%BF%85%E9%A0%88%EF%BC%89 52 | [6]: https://www.jssec.org/dl/android_securecoding/5_how_to_use_security_functions.html#network-security-configuration 53 | 54 | [^1]: dummy "中間者攻撃:通信している2人のユーザーの間に第三者が介在し、送信者と受信者の両方になりすまして、ユーザーが気付かないうちに通信を盗聴したり、制御したりすること" -------------------------------------------------------------------------------- /EasterEgg.md: -------------------------------------------------------------------------------- 1 | # Code contains easter egg (EasterEgg) 2 | 3 | ## 警告されている問題点 4 | 5 | ソースコード内にコメントに見せかけたプログラムが埋め込まれており、悪意のあるコードが実行されてしまう可能性があります。 6 | 7 | ``` 8 | このチェックはデフォルトで無効ですが、次の手順で有効にすることができます。 9 | 10 | 1. 「Settings」画面の表示 11 | ・Android Studio全体での設定の場合: 12 |  起動画面(「Welcome to Android Studio」画面)の右下「Configure」から「Settings」画面を開く 13 | ・プロジェクト単位での設定の場合: 14 |  プロジェクト画面の「File」メニューから「Settings...」画面を開く 15 | 2. EasterEggチェックの有効化 16 | 1. 左ペインでEditor -> Inspectionsを選択する 17 | 2. 右ペインでAndroid -> Lint -> Securityの一覧から"Code contains easter egg"のチェックをオンにする 18 | ``` 19 | 20 | ## 対策のポイント 21 | 22 | - 不適切なコメント文(実際は実行可能なコード)を削除する 23 | 24 | ## 対策の具体例 25 | 26 | ソースコードの検出された箇所を確認して、不適切なコメント文(実行可能コード)であればすべて削除してください。 27 | ペア・コーディングやソースコード・レビューでは、これを見逃さないようにしてください。 28 | 29 | ## 不適切な例 30 | 31 | 隠しコードを意図的に混入したり、放置したままリリースした場合、アプリの利用者が被害を受ける可能性があります。 32 | 33 | 以下の例では、"\u002a\u002f"(ASCIIコードでは"\*/")によりコメントを閉じ、実行可能なコードを続けて挿入し、行末に"\u002f\u002a"(ASCIIコードでは"/\*")を置くことで新しいコメントを開き、ブロック全体がコメントアウトされているように見せることで、実行可能なコードを埋め込んでいます。 34 | 35 | ```java 36 | // ... 37 | public class MainActivity extends AppCompatActivity { 38 | 39 | @Override 40 | protected void onCreate(Bundle savedInstanceState) { 41 | super.onCreate(savedInstanceState); 42 | setContentView(R.layout.activity_main); 43 | 44 | /*\u002a\u002f\u0042\u0075\u0074\u0074\u006f\u006e\u0020\u0074\u0061\u0070\u0048\u0065\u0072\u0065\u0020\u003d\u0020\u0028\u0042\u0075\u0074\u0074\u006f\u006e\u0029\u0066\u0069\u006e\u0064\u0056\u0069\u0065\u0077\u0042\u0079\u0049\u0064\u0028\u0052\u002e\u0069\u0064\u002e\u0074\u0061\u0070\u0048\u0065\u0072\u0065\u0029\u003b\u002f\u002a 45 | /*\u002a\u002f\u0074\u0061\u0070\u0048\u0065\u0072\u0065\u002e\u0073\u0065\u0074\u004f\u006e\u0043\u006c\u0069\u0063\u006b\u004c\u0069\u0073\u0074\u0065\u006e\u0065\u0072\u0028\u006e\u0065\u0077\u0020\u0056\u0069\u0065\u0077\u002e\u004f\u006e\u0043\u006c\u0069\u0063\u006b\u004c\u0069\u0073\u0074\u0065\u006e\u0065\u0072\u0028\u0029\u0020\u007b\u002f\u002a 46 | /*\u002a\u002f\u0040\u004f\u0076\u0065\u0072\u0072\u0069\u0064\u0065\u002f\u002a 47 | /*\u002a\u002f\u0070\u0075\u0062\u006c\u0069\u0063\u0020\u0076\u006f\u0069\u0064\u0020\u006f\u006e\u0043\u006c\u0069\u0063\u006b\u0028\u0056\u0069\u0065\u0077\u0020\u0076\u0029\u0020\u007b\u002f\u002a 48 | /*\u002a\u002f\u0054\u0065\u0078\u0074\u0056\u0069\u0065\u0077\u0020\u0074\u0065\u0078\u0074\u0056\u0069\u0065\u0077\u0020\u003d\u0020\u0028\u0054\u0065\u0078\u0074\u0056\u0069\u0065\u0077\u0029\u0066\u0069\u006e\u0064\u0056\u0069\u0065\u0077\u0042\u0079\u0049\u0064\u0028\u0052\u002e\u0069\u0064\u002e\u0074\u0065\u0078\u0074\u0056\u0069\u0065\u0077\u0029\u003b\u002f\u002a 49 | /*\u002a\u002f\u0074\u0065\u0078\u0074\u0056\u0069\u0065\u0077\u002e\u0073\u0065\u0074\u0054\u0065\u0078\u0074\u0028\u0022\u0057\u0065\u006c\u0063\u006f\u006d\u0065\u0020\u0074\u006f\u0020\u0045\u0061\u0073\u0074\u0065\u0072\u0020\u0045\u0067\u0067\u0021\u0022\u0029\u003b\u002f\u002a 50 | /*\u002a\u002f\u007d\u002f\u002a 51 | /*\u002a\u002f\u007d\u0029\u003b\u002f\u002a 52 | /**/ 53 | } 54 | } 55 | ``` 56 | 57 | 上のコメントの実態は以下のコードで、ボタンのタップでメッセージが表示されてしまいます。 58 | 59 | ```java 60 | /**/Button tapHere = (Button)findViewById(R.id.tapHere);/* 61 | /**/tapHere.setOnClickListener(new View.OnClickListener() {/* 62 | /**/@Override/* 63 | /**/public void onClick(View v) {/* 64 | /**/TextView textView = (TextView)findViewById(R.id.textView);/* 65 | /**/textView.setText("Welcome to Easter Egg!");/* 66 | /**/}/* 67 | /**/});/* 68 | /**/ 69 | ``` 70 | 71 | Lintは、ソースのコメント中に"\u002a\u002f"を検知すると、次のようなメッセージを出力します。 72 | 73 | - Lint出力(Warning) 74 | "Code might be hidden here; found unicode escape sequence which is interpreted as comment end, compiled code follows" 75 | 76 | 77 | [1]: http://www.i-programmer.info/history/computer-languages/2340-coded-easter-eggs.html -------------------------------------------------------------------------------- /ExportedContentProvider.md: -------------------------------------------------------------------------------- 1 | # Content provider does not require permission (ExportedContentProvider) 2 | 3 | ## 警告されている問題点 4 | 5 | ContentProviderのアクセス制御が不十分なため、第三者アプリからの操作による情報の漏洩や改竄のリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | ContentProviderに関して、以下のいずれかの対策を実施してください。 10 | 11 | - 第三者アプリからの利用を不許可にする 12 | - パーミッションを指定して利用可能なアプリを限定する 13 | - 利用を制限しないなら重要な情報を扱わない 14 | 15 | ## 対策の具体例 16 | 17 | ContentProviderのexported属性は、バージョンにより無効であったり、デフォルト値が異なるので、以下の例のように明示することを推奨します。 18 | 具体的には、Android 2.2(API 8)以前の端末ではContentProviderを非公開にできないため、Android 2.2(API 8)以前の端末を非サポートにする(minSdkVersionを9以上にする)ことが必要です。デフォルト値については、targetSdkVersionが16以下で公開(true)、17以上で非公開(false)です。 19 | また、すべての場合において受信データの安全性を確認することが前提となります。 20 | 21 | ### 第三者アプリからの利用を不許可にする 22 | 23 | 他アプリからの利用を許可しない場合はContentProviderを非公開としてください。 24 | 下に示す例のように、<provider>でexported属性をfalseに設定することで、他アプリからのアクセスを不許可にできます。 25 | 26 | ``` 27 | 31 | 32 | 35 | 36 | 40 | 41 | 42 | 43 | ``` 44 | 45 | ### パーミッションを指定して利用可能なアプリを限定する 46 | 47 | 以下にパーミッション指定によるいくつかの対策例を示します。必要に応じて、ContentProviderのデータのパスを限定したり、[権限の再移譲問題][6]が起きないようにパーミッションを設定してください。 48 | 49 | 最初に、扱うデータが連絡先(Contacts)情報の場合で、アクセスをパーミッションで許可する例を示します。 50 | 下の例では、第三者アプリはREAD_CONTACTSパーミッションを持たなければContentProviderを利用できません。 51 | 52 | ``` 53 | 54 | 55 | : 56 | 57 | 58 | 63 | 64 | : 65 | 66 | : 67 | 68 | ``` 69 | 70 | ContentProviderは他のコンポーネント(Activity, Service, BroadcastReceiver)と異なり、読み書き2つのパーミッションの設定が可能です。 71 | 72 | 次の例では、読み書きそれぞれにパーミッションを設定しています。第三者アプリは、READ\_CONTACTSパーミッションを持たなければContentProviderからの情報を読み取るqueryメソッドを利用することができません。同様に、WRITE\_CONTACTSパーミッションを持たなければinsert、update、およびdeleteメソッドによる書き込みが制限されます。 73 | 74 | ``` 75 | 76 | 77 | : 78 | 79 | 80 | 86 | 87 | : 88 | 89 | : 90 | 91 | ``` 92 | 93 | 次の例は、アクセスを許可する情報の範囲を特定のパターンにマッチするパスに限定しています。 94 | path-permissionタグでは、さらに細かくパスやパーミッションを設定することも可能です。詳細は[Android Developers][3]を参照してください。 95 | ``` 96 | 97 | 98 | 99 | : 100 | 101 | 102 | 103 | 108 | 111 | 112 | 113 | : 114 | 115 | : 116 | 117 | ``` 118 | 119 | ### 利用を制限しないなら重要な情報を扱わない 120 | 121 | ContentProviderを公開し、パーミッションによる制限もせずに第三者アプリからの利用を許可する場合、不正なデータを受信することを前提にアプリを設計・実装してください。特に、結果を返す時に重要な情報を含めてはいけません。 122 | ContentProviderをパーミッションで制限せずに公開する状態は、不適切な例と重なるためLintはメッセージを出力します。 123 | 124 | ## 不適切な例 125 | 126 | 以下の例では、targetSdkVersionが16以下の場合、ContentProviderが制限なく公開されるため、マルウェアなどに不正なアクセスを許し、情報の漏洩や改竄のリスクがあります。 127 | 128 | ``` 129 | 130 | 131 | : 132 | 134 | 135 | 138 | 139 | 140 | 141 | ``` 142 | 143 | Lintは、ContentProviderがパーミッションもパスも制限なく公開されていることを検知すると、次のようなメッセージを出力します。 144 | 145 | - Lint出力(Warning) 146 | “Exported content providers can provide access to potentially sensitive data.” 147 | 148 | ## 外部リンク 149 | 150 | - [Content Provider | Android Developers][1] 151 | - [Content Providerのガイド][2] 152 | - [<path-permission> | Android Developers][3] 153 | - [Androidアプリのセキュア設計・セキュアコーディングガイド][4] 154 | [「4.3 Content Providerを作る・利用する」][4.3]にContent Providerを安全に使用するための指針や実装例が解説されています 155 | [「5.2 PermissionとProtection Level」][5.2]にパーミッションの適切な使用方法の解説があります 156 | 157 | [1]:https://developer.android.com/reference/android/content/ContentProvider.html 158 | [2]:https://developer.android.com/guide/topics/providers/content-providers.html 159 | [3]:https://developer.android.com/guide/topics/manifest/path-permission-element.html 160 | [4]:http://www.jssec.org/dl/android_securecoding/ 161 | [4.3]:http://www.jssec.org/dl/android_securecoding/4_using_technology_in_a_safe_way.html#content-provider%E3%82%92%E4%BD%9C%E3%82%8B%E3%83%BB%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B 162 | [5.2]:http://www.jssec.org/dl/android_securecoding/5_how_to_use_security_functions.html#permission%E3%81%A8protection-level 163 | [6]:http://www.jssec.org/dl/android_securecoding/5_how_to_use_security_functions.html#permission%E3%81%AE%E5%86%8D%E5%A7%94%E8%AD%B2%E5%95%8F%E9%A1%8C 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /ExportedPreferenceActivity.md: -------------------------------------------------------------------------------- 1 | # PreferenceActivity should not be exported (ExportedPreferenceActivity) 2 | 3 | ## 警告されている問題点 4 | 5 | [脆弱性のあるPreferenceActivity][1]のサブクラスを公開しているため、アプリ内のFragmentが任意のパラメータで起動されてしまうリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | PreferenceActivityサブクラス利用に関して、以下のいずれかの対策を行ってください。 10 | 11 | - PreferenceActivityサブクラスを非公開にする(minSdkVersion18以下なら原則必須) 12 | - 有効なFragmentであることを確認する 13 | 14 | 通常のActivityに関しては、別の対策が必要です。[Androidアプリのセキュア設計・セキュアコーディングガイド][0]を参考にしてください。 15 | 16 | ## 対策の具体例 17 | 18 | ### PreferenceActivityサブクラスを非公開にする 19 | 20 | Android 4.3(API 18)以前の端末では、脆弱性を利用した攻撃が有効になるため、第三者アプリから利用できないようにすべてのPreferenceActivityサブクラスを非公開にしてください。 21 | API19以降でも、第三者アプリからのActivity起動が必要ない場合は同様に非公開にしてください。 22 | 23 | ``` 24 | 26 | 29 | 30 | ``` 31 | 32 | ### Fragmentを確認する 33 | 34 | minSdkVersionが19以上の場合、PreferenceActivityサブクラスは、呼び出しFragmentの名前で使用の可不可を判定する必要があります。 35 | 36 | ```java 37 | public class MyPreferenceActivity extends PreferenceActivity { 38 | @Override 39 | public void onCreate(Bundle savedInstanceState) { 40 | ... 41 | } 42 | 43 | @Override 44 | protected boolean isValidFragment(String fragmentName) { 45 | // fragmentNameを確認して、想定しているものだけを通す 46 | return XXXFragment.class.getName().equals(fragmentName) || 47 | YYYFragment.class.getName().equals(fragmentName); 48 | } 49 | } 50 | ``` 51 | 52 | Android 4.3(API 18)以前の端末では、上記実装があっても有効に働かないので原則非公開にしてください。 53 | 54 | ## 不適切な例 55 | 56 | targetSdkVersionが19以上では、マニフェストでPreferenceActivityサブクラスを公開に設定し、isValidFragmentメソッドをオーバーライドしていない場合、常にRuntimeExceptionが発生します。 57 | これを回避するため常にisValidFragmentメソッドがtrueを返すようにオーバーライドすると、このActivityが悪用されるリスクがあります。 58 | 59 | ``` 60 | 61 | 62 | 64 | ``` 65 | 66 | ``` 67 | import android.preference.PreferenceActivity; 68 | import android.os.Bundle; 69 | 70 | public class MyPreferenceActivity extends PreferenceActivity { 71 | @Override 72 | public void onCreate(Bundle savedInstanceState) { 73 | // ... 74 | } 75 | 76 | @Override 77 | protected boolean isValidFragment(String fragmentName) { 78 | return true; // すべてのFragmentによる起動が許可される 79 | } 80 | } 81 | ``` 82 | 83 | Lintは、公開されているPreferenceActivityサブクラスのisValidFragmentメソッドがオーバーライドされていない(コードの正誤は検知しません)ことを検知すると、次のようなメッセージを出力します。 84 | 85 | - Lint出力(Warning) 86 | "\`PreferenceActivity\` subclass \`com.example.exportedpreferenceactivity.MyPreferenceActivity\` should not be exported" 87 | 88 | targetSdkVersionが18以下の場合、isValidFragmentメソッドはオーバーライドの有無にかかわらず常にtrueを返します。 89 | 90 | ## 外部リンク 91 | 92 | - [A New Vulnerability in the Android Framework: Fragment Injection][1] 93 | - [Fragment Injection脆弱性を修正する方法][2] 94 | - [Androidアプリのセキュア設計・セキュアコーディングガイド 4.1.3.6.PreferenceActivityのFragment Injection対策について][3] 95 | 96 | 97 | [0]: http://www.jssec.org/dl/android_securecoding/4_using_technology_in_a_safe_way.html#activity%E3%82%92%E4%BD%9C%E3%82%8B%E3%83%BB%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B 98 | [1]: http://securityintelligence.com/new-vulnerability-android-framework-fragment-injection 99 | [2]: https://support.google.com/faqs/answer/7188427?hl=ja 100 | [3]: http://www.jssec.org/dl/android_securecoding/4_using_technology_in_a_safe_way.html#preferenceactivity%E3%81%AEfragment-injection%E5%AF%BE%E7%AD%96%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6 -------------------------------------------------------------------------------- /ExportedReceiver.md: -------------------------------------------------------------------------------- 1 | # Receiver does not require permission (ExportedReceiver) 2 | 3 | ## 警告されている問題点 4 | 5 | Receiverのアクセス制御が不十分なため、不正なブロードキャストによる情報の改竄や漏洩のリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | 以下のいずれかの対策を実施してください。 10 | 11 | - 第三者アプリからブロードキャストを受信しない 12 | - パーミッションを指定して受信するブロードキャストを限定する 13 | - 受信するブロードキャストを制限しないなら重要な情報を扱わない 14 | 15 | ## 対策の具体例 16 | 17 | Receiverのexported属性が無指定である場合にそのReceiverが公開されるか非公開となるかは、intent-filterの定義の有無で変化します。 18 | 最初にコードを書くときにはその挙動を理解できていると思いますが、後の修正や他の開発者のためにも、以下の例のようにexported属性を明示することを推奨します。 19 | また、すべての場合において[受信Intentの安全性を確認する][UnsafeProtectedBroadcastReceiver]ことが前提となります。 20 | 21 | ### 第三者アプリからブロードキャストを受信しない 22 | 23 | 他アプリからBroadcastを受信する必要がない場合は、Receiverを非公開としてください。 24 | exported属性を設定せず、intent-filterを持たない場合は非公開となるのがデフォルトの挙動ですが、明示的に非公開に設定します。 25 | 26 | ``` 27 | 28 | 32 | 33 | 36 | 37 | 53 | 57 | 58 | 59 | 60 | 63 | 64 | 67 | 68 | 69 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | ``` 83 | 84 | 下の例のように親の<application>でパーミッションの設定を行った場合も、下位の<receiver>に対するパーミッションの設定が有効となります。 85 | 86 | ``` 87 | 88 | 92 | 93 | 94 | 95 | 98 | 99 | 100 | 104 | 105 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | ``` 118 | 119 | 詳細は [Android アプリのセキュア設計・セキュアコーディングガイド 5.2. Permission と Protection Level][6-2]を参照してください。 120 | 121 | ### 受信するブロードキャストを制限しないなら重要な情報を扱わない 122 | 123 | Receiverを公開し、パーミッションによる制限もせずに第三者アプリからのブロードキャストを受信する場合、不正なデータを受信することを前提にアプリを設計・実装してください。特に、結果を返す時に重要な情報を含めてはいけません。 124 | ブロードキャストをパーミッションで制限せずに公開する状態は不適切な例と重なるため、Lintはメッセージを出力します。 125 | 126 | ## 不適切な例 127 | 128 | 下の例では、exported属性の設定がありませんが<intent-filter>があるため暗黙的に公開となります。パーミッションによる保護もないため、重要情報などを返すようになっていると情報漏洩などのリスクがあります。 129 | 130 | ``` 131 | 132 | 136 | 137 | 140 | 141 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | ``` 152 | 153 | Lintは、公開されているReceiverに対しパーミッションの設定がないことを検知すると、次のようなメッセージを出力します。 154 | 155 | - Lint 出力(Warning) 156 | "Exported receiver does not require permission." 157 | 158 | ## 外部リンク 159 | 160 | - [<receiver> | Developer][1] 161 | - [BroadcastReceiver | Android Developers][2] 162 | - [Broadcast一般に関する解説記事][3] 163 | - [<application> | Developer][4] 164 | - [InstallReferrerReceiver][5] 165 | - [Android アプリのセキュア設計・セキュアコーディングガイド][6] 166 | [「4.2. Broadcast を受信する・送信する」][6-1]に Receiver を安全に使用するための指針や実装例が解説されています 167 | 168 | 169 | [1]:https://developer.android.com/guide/topics/manifest/receiver-element.html 170 | [2]:https://developer.android.com/reference/android/content/BroadcastReceiver.html 171 | [3]:https://developer.android.com/guide/components/broadcasts.html 172 | [4]:https://developer.android.com/guide/topics/manifest/application-element.html 173 | [5]:https://developers.google.com/android/reference/com/google/android/gms/tagmanager/InstallReferrerReceiver 174 | [6]:http://www.jssec.org/dl/android_securecoding/ 175 | [6-1]:http://www.jssec.org/dl/android_securecoding/4_using_technology_in_a_safe_way.html#broadcast%E3%82%92%E5%8F%97%E4%BF%A1%E3%81%99%E3%82%8B%E3%83%BB%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B 176 | [6-2]:http://www.jssec.org/dl/android_securecoding/5_how_to_use_security_functions.html#permission%E3%81%A8protection-level 177 | 178 | [UnsafeProtectedBroadcastReceiver]: UnsafeProtectedBroadcastReceiver.md 179 | 180 | -------------------------------------------------------------------------------- /ExportedService.md: -------------------------------------------------------------------------------- 1 | # Exported service does not require permission (ExportedService) 2 | 3 | ## 警告されている問題点 4 | 5 | Serviceのアクセス制御が不十分なため、不正利用による情報の改竄や漏洩のリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | 以下のいずれかの対策を実施してください。 10 | 11 | - 第三者アプリからの利用を不許可にする 12 | - パーミッションを指定して利用可能なアプリを限定する 13 | - 利用を制限しないなら重要な情報を扱わない 14 | 15 | ## 対策の具体例 16 | 17 | Serviceのexported属性が無指定の時に公開となるか非公開となるかは、intent-filterの定義の有無で変化します。 18 | 最初にコードを書くときにはその挙動を理解できていると思いますが、後の修正や他の開発者のためにも、以下の例のようにexported属性を明示することを推奨します。 19 | また、すべての場合において受信Intentの安全性を確認することが前提となります。 20 | 21 | ### 第三者アプリからの利用を不許可にする 22 | 23 | 他アプリからの利用を許可しない場合は、Serviceを非公開としてください。 24 | exported属性を設定せず、intent-filterを持たない場合は非公開となるのがデフォルトの挙動ですが、明示的に非公開に設定します。 25 | 26 | ``` 27 | 28 | 32 | 33 | 34 | 37 | 38 | 43 | 44 | 45 | 46 | ``` 47 | 48 | ### パーミッションを指定して利用可能なアプリを限定する 49 | 50 | Serviceに対してパーミッションを設定することで、利用側に同じパーミッションが必要となります。 51 | 下の例では、自社製アプリとの連携を前提に保護レベルを"signature"に設定した独自パーミッションを定義し、同じ秘密鍵で署名したアプリ(APK)からのみ呼び出しが可能な設定にしています。 52 | 53 | ``` 54 | 55 | 59 | 60 | 61 | 62 | 65 | 66 | 69 | 70 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | ``` 84 | 85 | 下に示す例のように親のapplicationタグにパーミッションの設定を行った場合も、子要素のserviceに対するパーミッションの設定が有効となります。 86 | 87 | ``` 88 | 89 | 93 | 94 | 95 | 96 | 99 | 100 | 101 | 105 | 106 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | ``` 119 | 120 | 詳細は [Android アプリのセキュア設計・セキュアコーディングガイド][3-2]を参照してください。 121 | 122 | ### 利用を制限しないなら重要な情報を扱わない 123 | 124 | Serviceを公開し、パーミッションによる制限もせずに第三者アプリからの利用を許可する場合、不正なデータを受信することを前提にアプリを設計・実装してください。特に、結果を返す時に重要な情報を含めてはいけません。 125 | Serviceをパーミッションで制限せずに公開する状態は、不適切な例と重なるためLintはメッセージを出力します。 126 | 127 | ## 不適切な例 128 | 129 | 下の例では、exported属性の設定がありませんがintent-filterの定義があるため暗黙的に公開となります。パーミッションによる保護もないため、重要情報などを返すようになっていると情報漏洩などのリスクがあります。 130 | 131 | ``` 132 | 133 | 137 | 138 | 141 | 142 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | ``` 154 | 155 | Lintは、公開されているServiceに対してパーミッションの設定がないことを検知すると、次のようなメッセージを出力します。 156 | 157 | - Lint出力(Warning) 158 | "Exported service does not require permission." 159 | 160 | ## 外部リンク 161 | 162 | - [Service | Android Developers][1] 163 | - [<service> | Android Developers][2] 164 | - [Android アプリのセキュア設計・セキュアコーディングガイド][3] 165 | [「4.4. Service を作る・利用する」][3-1]に Service を安全に使用するための指針や実装例が解説されています 166 | 167 | [1]:https://developer.android.com/guide/components/services.html 168 | [2]:https://developer.android.com/guide/topics/manifest/service-element.html 169 | [3]:http://www.jssec.org/dl/android_securecoding/ 170 | [3-1]:http://www.jssec.org/dl/android_securecoding/4_using_technology_in_a_safe_way.html#service%E3%82%92%E4%BD%9C%E3%82%8B%E3%83%BB%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B 171 | [3-2]:http://www.jssec.org/dl/android_securecoding/5_how_to_use_security_functions.html#permission%E3%81%A8protection-level 172 | 173 | -------------------------------------------------------------------------------- /GetInstance.md: -------------------------------------------------------------------------------- 1 | # Cipher.getInstance with ECB (GetInstance) 2 | 3 | ## 警告されている問題点 4 | 5 | 安全とされる暗号方式を指定していないため、情報漏洩や改竄のリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - ブロック暗号のモード、およびパディングは、推奨されるものを明示的に指定する 10 | 11 | ## 対策の具体例 12 | 13 | javax.crypto.CipherクラスのgetInstanceメソッドの引数のモードとしてECBを指定することは避け、以下の例に示すような[安全とされているアルゴリズム/モード/パディングの組み合わせ][2]を使用してください。 14 | 15 | ```java 16 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 17 | ``` 18 | 19 | ```java 20 | Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); 21 | ``` 22 | 23 | ## 不適切な例 24 | 25 | ### モード/パディング指定を省略する 26 | 27 | getInstanceメソッドのパラメータは、アルゴリズム/モード/パディング、もしくはアルゴリズムのみの指定が可能です。 28 | アルゴリズムのみを指定した場合、Androidは[欠点のあるECB][3]をモードとして選択することがあり、安全ではありません。 29 | 30 | ```java 31 | Cipher cipher = Cipher.getInstance("AES"); // アルゴリズムのみ指定 32 | ``` 33 | 34 | Lintは、上の例のようにgetInstanceメソッドにアルゴリズムのみの指定を検知すると、次のようなメッセージを出力します。 35 | 36 | - Lint出力(Warning) 37 | "\`Cipher.getInstance` should not be called without setting the encryption mode and padding" 38 | ただし、API26以降に追加されたAES_128やAES_256を指定した場合には検知しません。 39 | 40 | ### ECBモードを指定する 41 | 42 | [欠点のあるECB][3]をモードとして指定することは安全ではありません。 43 | 44 | ```java 45 | Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); // モードとしてECBを指定 46 | ``` 47 | 48 | Lintは、上の例のようにgetInstanceメソッドにECBのモード指定を検知すると、次のようなメッセージを出力します。 49 | 50 | - Lin結果(Warning) 51 | "ECB encryption mode should not be used" 52 | 53 | ## 外部リンク 54 | 55 | - [Cipher | Android Developers][1] 56 | - CRYPTREC[『電子政府における調達のために参照すべき暗号のリスト(CRYPTREC暗号リスト)』][2] 57 | - IPA[『ブロック暗号を使った秘匿、メッセージ認証、および認証暗号を目的とした利用モードの技術報告書』][3] 58 | 59 | 60 | 61 | [1]: https://developer.android.com/reference/javax/crypto/Cipher.html 62 | [2]: http://www.cryptrec.go.jp/list/cryptrec-ls-0001-2016.pdf 63 | [3]: https://www.ipa.go.jp/security/enc/CRYPTREC/fy15/documents/mode_wg040607.pdf#page=34 -------------------------------------------------------------------------------- /GrantAllUris.md: -------------------------------------------------------------------------------- 1 | # Content provider shares everything (GrantAllUris) 2 | 3 | ## 警告されている問題点 4 | 5 | ContentProviderの全リソース利用が他のアプリに許可されているため、重要な情報が漏洩・改竄されるリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - アクセスを許可するリソースを必要最小限にする 10 | 11 | ## 対策の具体例 12 | 13 | 下の例は、リソースの一時的なアクセスを"/for_sharing/this_directory_only/"以下に限定するための設定です。 14 | 15 | ``` 16 | 17 | 18 | 23 | 24 | 25 | 26 | ``` 27 | 28 | pathPrefix属性の他にpath属性、pathPattern属性を使用できます。併用も可能です。 29 | 詳しくは[Android Developers][0]を参照してください。 30 | 31 | より詳細なアクセス制御を行うには、[Content provider does not require permission][4]の項も参照してください。 32 | 33 | ## 不適切な例 34 | 35 | アクセス可能なリソースのパスの指定には、path属性、pathPrefix属性、およびpathPttern属性の3種類があります。 36 | 以下は、それぞれアクセス可能なリソースのパスを指定していますが、どれもすべてのリソースに対するアクセスを許可する設定になっているため、情報漏洩・改竄のリスクがあります。 37 | 38 | ``` 39 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | ``` 49 | Lintは、grant-uri-permission属性のパス指定が “/” となっているものを検知すると、次のようなメッセージを出力します。 50 | 51 | - Lint出力(Warning) 52 | "Content provider shares everything; this is potentially dangerous." 53 | 54 | このメッセージはexported属性をfalse(非公開)に設定していても出力されます。 55 | 56 | ## 外部リンク 57 | 58 | - [Content Provider | Android Developers][1] 59 | - [Content Provider のガイド][2] 60 | - [Android アプリのセキュア設計・セキュアコーディングガイド 4.3. Content Provider を作る・利用する][3] 61 | 62 | [0]: https://developer.android.com/guide/topics/manifest/grant-uri-permission-element 63 | [1]: https://developer.android.com/reference/android/content/ContentProvider.html 64 | [2]: https://developer.android.com/guide/topics/providers/content-providers.html 65 | [3]: http://www.jssec.org/dl/android_securecoding/4_using_technology_in_a_safe_way.html#content-provider%E3%82%92%E4%BD%9C%E3%82%8B%E3%83%BB%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B 66 | [4]: ExportedContentProvider.md 67 | 68 | 69 | -------------------------------------------------------------------------------- /HardcodedDebugMode.md: -------------------------------------------------------------------------------- 1 | # Hardcoded value of android:debuggable in the manifest (HardcodedDebugMode) 2 | 3 | ## 警告されている問題点 4 | 5 | デバッグ情報やデバッグ専用機能を含んだ状態でアプリをビルドし、設計上の内部情報や秘匿情報を公開してしまうリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - 人為的ミスの原因となるため、設定ファイルでデバッグモード切替を行わないようにする 10 | 11 | ## 対策の具体例 12 | 13 | 以前のAndroid Studioでは、debuggable属性を切り替えてデバッグモードを変更していましたが、現在は明示されていなければ、ビルドタイプに応じて自動で適用されます。 14 | そのため、Android Studio利用時にはマニフェストのapplicationタグにdebuggable属性を設定しない方が利便性が高くなります。 15 | 16 | ``` 17 | 19 | 20 | 21 | 25 | 26 | 27 | 28 | ``` 29 | 30 | [Build Variants][2]を利用して、デバッグと本番リリースのAPKを生成し分けるのが正しい手法とされます。これを利用すると「広告つきの無料版」 と 「広告なしの有料版」といったようにアプリの派生バージョンの管理も可能になります。 31 | 32 | ## 不適切な例 33 | 34 | AndroidManifest.xmlにdebuggable属性が記述されていると、ビルドの種類にかかわらず常にその値を使用します。リリース時、この設定の変更を忘れると、デバッグ情報やデバッグ専用機能を含んだアプリを公開してしまう危険性があります。 35 | 36 | ``` 37 | 39 | 40 |   45 | 46 | 47 | 48 | ``` 49 | 50 | Lintは、上の例のようにdebuggable属性の設定を検知すると、次のようなメッセージを出力します。 51 | 52 | - Lint出力(Error) 53 | "Avoid hardcoding the debug mode; leaving it out allows debug and release builds to automatically assign one" 54 | 55 | ## 外部リンク 56 | 57 | - [AndroidManifest.xmlの属性値][1] 58 | 59 | [1]: https://developer.android.com/guide/topics/manifest/application-element.html 60 | [2]: https://developer.android.com/studio/build/build-variants.html?hl=ja 61 | 62 | 63 | -------------------------------------------------------------------------------- /HardwareIds.md: -------------------------------------------------------------------------------- 1 | # Hardware Id Usage (HardwareIds) 2 | 3 | ## 警告されている問題点 4 | 5 | デバイス(端末)に基づく識別子を個人情報に関連付けている場合、不正アクセスや、ユーザーのプライバシー侵害のリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - デバイスに基づく識別子を個人情報に紐づけて用いることを避ける 10 | 11 | ## 対策の具体例 12 | 13 | アプリの目的・用途を考慮し、以下の識別子の利用を検討してください。 14 | 15 | |識別子|特徴| 16 | |:----:|:----| 17 | |広告ID|ユーザーがリセットできる匿名かつ固有の識別子で、広告のユースケースに適している| 18 | |インスタンスID|アプリがインストールされている間だけ維持されるため、比較的簡単にリセット可能| 19 | |UUID|グローバルに一意であるため、特定のアプリインスタンスの識別に使用可能| 20 | 21 | ### 広告IDを利用する 22 | 23 | 広告とユーザーの分析を目的とする場合は、以下の方法で取得できる広告IDを使用してください。 24 | ただし、取得前に「インタレストベース広告をオプトアウト」の設定のステータスを確認してください。 25 | 26 | ```java 27 | import com.google.android.gms.ads.identifier.AdvertisingIdClient; 28 | : 29 | String AdId = null; 30 | 31 | try { 32 | AdvertisingIdClient.Info info = AdvertisingIdClient.getAdvertisingIdInfo(context); 33 | //「インタレストベース広告をオプトアウト」の設定を確認した上で広告IDを取得する 34 | if (info.isLimitAdTrackingEnabled()) { 35 | // チェックされていてもgetIdメソッドは広告IDを取得しますが、設定を尊重してください 36 | ... 37 | } else { 38 | AdId = info.getId(); 39 | } 40 | } catch (IOException e) { // GooglePlayServices接続失敗 41 | ... 42 | } catch (GooglePlaySericesNotAvailableException e) { // GooglePlay未インストール 43 | ... 44 | } catch (GooglePlayServicesRepairableException e) { // GooglePlayServices使用不可 45 | ... 46 | } 47 | ``` 48 | 49 | 広告IDを利用する場合、Googleの定めた[広告IDの利用規約][4]に従ってください。 50 | 51 | ### インスタンスIDを利用する 52 | 53 | Google提供のInstance ID Serviceを利用し、アプリのインスタンスごとにユニークな識別子を取得することができます。 54 | この識別子はアプリのインスタンスを識別し、トラッキングに用いることが可能ですが、Google Playによって配布されたアプリに限られます。 55 | 56 | ```java 57 | // 発行済みのInstance IDを取得する 58 | String iid = InstanceID.getInstance(context).getId() 59 | 60 | // 実際の識別にはトークンを取得して確認する 61 | String authorizedEntity = PROJECT_ID; // Google Developer Consoleが生成するProject idが必要 62 | String scope = "GCM"; 63 | String token = InstanceID.getInstance(context).getToken(authorizedEntity, scope); 64 | : 65 | ``` 66 | 67 | インスタンスIDおよびその利用方法についての詳細は[InstanceID Androidでの実装][7]や[Google API InstaceID解説][8]を参照してください。 68 | 69 | ### UUID を利用する 70 | 71 | インスタンスIDが利用できないケースではUUIDを利用して、アプリのインスタンスごとにユニークなIDを割り振る方法もあります。UUIDを作成するにはjava.util.UUIDクラスを利用します。 72 | 73 | 74 | ```java 75 | String uniqueID = UUID.randomUUID().toString(); 76 | ``` 77 | 78 | 詳細は[Working with Instance IDs and GUIDs][9]を参照してください。 79 | 80 | ## 不適切な例 81 | 82 | ハードウェアに紐づいた識別子は、 83 | 84 | - ユーザーが値を変えることが出来ない、または困難 85 | - 複数のアプリが同一の値を利用する 86 | 87 | といった特徴を持つため、以下のようなリスクが考えられます。 88 | 89 | - 長期間のユーザートラッキング 90 | - 個々のアプリが扱う情報の「名寄せ」によるプライバシー侵害 91 | - 前のデバイス所有者の情報へのアクセス 92 | 93 | 名寄せによる個人情報収集においては、個々のアプリが扱う情報では個人を特定できなくても、それらの情報を集めると機微な個人情報が浮き彫りになる可能性があります。 94 | 以上のことから、下表に示すようなデバイスに紐づく識別子を認証のベースとして用いたり、ユーザー情報と一緒に扱うことは推奨されていません。 95 | 96 | |識別子|特徴| 97 | |:----:|:----| 98 | |BluetoothおよびWi-FiのMACアドレス|スキャンする時はパーミッションが必要| 99 | |ANDROID ID|端末の最初の設定時に生成され、ファクトリーリセットで値を再生成| 100 | |Telephony Managerに関する情報|READ_PHONE_STATEパーミッションが必要| 101 | |シリアル番号|Android2.3以上の非携帯電話端末と一部の携帯電話端末で取得可能| 102 | 103 | ### MACアドレスを使用する 104 | 105 | BluetoothやWi-FiのMACアドレスは完全にデバイスに紐づいており、識別子として用いることは前述のとおり不適切です。 106 | 107 | ```java 108 | BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 109 | // BluetoothのMACアドレスを取得 110 | String bluetoothAddress = adapter.getAddress(); 111 | 112 | WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE); 113 | WifiInfo info = wm.getConnectionInfo(); 114 | // Wi-FiのMACアドレスを取得 115 | String wifiAddress = info.getMacAddress(); 116 | ``` 117 | 118 | Lintは、上のようにBluetoothAdapter.getAddressメソッドおよびWifiInfo.getMacAddressメソッドの呼び出しを検知すると、次のようなメッセージを出力します。 119 | 120 | - Lint出力(Warning) 121 | "using 'getAddress' to get identifiers is not recommended." 122 | "using 'getMacAddress' to get identifiers is not recommended." 123 | 124 | Android 6.0(API 23)でMACアドレスは常に`02:00:00:00:00:00`を返すようになり、真値の取得は不可能になっています。 125 | 126 | ### ANDROID IDを使用する 127 | 128 | 下記のようにして取得できる文字列(Android ID)はデバイスに紐づいており、識別子として用いることは前述のとおり不適切です。 129 | 130 | ``` 131 | // Android IDを取得 132 | String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); 133 | ``` 134 | 135 | Lintは、上のようにAndroid IDを取得しているのを検出すると、次のようなメッセージを出力します。 136 | 137 | - Lint出力(Warning) 138 | "using 'getString' to get identifiers is not recommended." 139 | 140 | ### Telephony Managerから取得可能な識別子を使用する 141 | 142 | Telephony Managerから以下のようなデバイスに紐づいた値を取得可能ですが、これらを識別子として使用することは前述のとおり不適切です。 143 | 144 | ``` 145 | TelephonyManager telMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); 146 |     // デバイスIDを取得 147 |     St ring deviceid = telMgr.getDeviceId(); 148 |     // 電話番号を取得 149 |     String phoneNumber = telMgr.getLine1Number(); 150 |     // SIMシリアルナンバーを取得 151 |     String simSerialNumber = telMgr.getSimSerialNumber(); 152 |     // サブスクライバーIDを取得 153 |     String subscriberId = telMgr.getSubscriberId(); 154 | ``` 155 | 156 | Lintは、上のようなメソッドの呼び出しを検知すると、それぞれ次のようなメッセージを出力します。 157 | 158 | - Lint出力(Warning) 159 | "using 'getDeviceId' to get identifiers is not recommended." 160 | "using 'getLine1Number' to get identifiers is not recommended." 161 | "using 'getSerial' to get identifiers is not recommended." 162 | "using 'getSubscriberId' to get identifiers is not recommended." 163 | 164 | ### デバイスのシリアル番号を使用する 165 | 166 | デバイスのシリアル番号を識別子として使用することは前述のとおり不適切です。 167 | 168 | ``` 169 | import java.lang.reflect.Method; 170 | : 171 | String serialNo; 172 | 173 | // SERIALプロパティ利用 174 | serialNo = android.os.Build.SERIAL; 175 | 176 | // 内部API利用 177 | try { 178 | Class c = Class.forName("android.os.SystemProperties"); 179 | Method get = c.getMethod("get", String.class); 180 | serialNo = (String) get.invoke(null, "ro.serialno"); 181 | } catch (Exception e) { 182 | } 183 | 184 | // getSerialメソッド利用 185 | serialNo = android.os.Build.getSerial(); 186 | ``` 187 | 188 | Lintは、上のようなシリアル番号の取得を検知すると、それぞれ次のようなメッセージを出力します。 189 | 190 | - Lint出力(Warning) 191 | "using ‘SERIAL’ to get identifiers is not recommended." 192 | "using ‘ro.serial’ to get identifiers is not recommended." 193 | 194 | getSerialメソッドでは、このパターンのメッセージを出力しませんが、不適切なことに変わりありません。 195 | 196 | ## 外部リンク 197 | 198 | - [一意識別子のベストプラクティス][1] 199 | - [AdvertisingIdClient | Android Developers][2] 200 | - [AdvertisingIdClient.Info | Android Developers][3] 201 | - [広告IDの利用規約][4] 202 | - [InstanceID | Android Developers][5] 203 | - [インスタンスIDとは何か][6] 204 | - [InstanceID Androidでの実装][7] 205 | - [Google API InstaceID解説][8] 206 | - [Working with Instance IDs and GUIDs][9] 207 | 208 | [1]:https://developer.android.com/training/articles/user-data-ids.html 209 | [2]:https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient 210 | [3]:https://developers.google.com/android/reference/com/google/android/gms/ads/identifier/AdvertisingIdClient.Info 211 | [4]:https://play.google.com/intl/ja_ALL/about/monetization-ads/ads/ad-id/ 212 | [5]:https://developers.google.com/android/reference/com/google/android/gms/iid/InstanceID 213 | [6]:https://developers.google.com/instance-id/ 214 | [7]:https://developers.google.com/instance-id/guides/android-implementation 215 | [8]:https://developers.google.com/android/reference/com/google/android/gms/iid/InstanceID 216 | [9]:https://developer.android.com/training/articles/user-data-ids.html#working_with_instance_ids_&_guids 217 | 218 | -------------------------------------------------------------------------------- /InvalidPermission.md: -------------------------------------------------------------------------------- 1 | # Invalid Permission Attribute (InvalidPermission) 2 | 3 | ## 警告されている問題点 4 | 5 | マニフェストでのパーミッション指定が無効なため、期待する保護が得られず、機能の不正利用や情報の漏洩・改竄のリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - 保護すべき機能・情報を確認し、適切なコンポーネントにパーミッションを指定してください。 10 | 11 | ## 対策の具体例 12 | 13 | パーミッションは、Androidが提供するコンポーネント(Activity、ContentProvider、Service、BroadcastReceiver)に対して設定します。 14 | 15 | マニフェストでパーミッション(permission属性) の設定が有効なタグは以下の7個で、それ以外の場所で設定した場合は無視されます。 16 | <activity>, <application>, <provider>, <service>, <receiver>, <activity-alias>, <path-permission> 17 | 18 | 下の例は<activity>に対して設定しています。 19 | 20 | ``` 21 | 22 | 25 | 26 | 29 | 30 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | ``` 42 | 43 | パーミッションの使い方の詳細は、[Defining Permissions | Android Developers][1]やAndroid アプリのセキュア設計・セキュアコーディングガイドの[5.2. Permission と Protection Level][2]などを参照してください。 44 | 45 | ## 不適切な例 46 | 47 | 下の例では、permission属性が無効なactionタグに対して属性を指定しているため、READ_CONTACTSパーミッションを持たないアプリからもアクセスが可能です。 48 | 49 | ``` 50 | 51 | 54 | 55 | 58 | 61 | 62 | 63 | 65 | 66 | 67 | : 68 | ``` 69 | 70 | Lintは、permission属性が無効なタグに対する設定を検知すると、次のようなメッセージを出力します。 71 | 72 | - Lint出力(warning) 73 | "Protecting an unsupported element with a permission is a non-op and potentially dangerous." 74 | 75 | 注意: permissionタグに対する設定は無効ですが、Lintはこれを検知しません。逆に、path-permissionタグは設定が有効ですが、Lintはメッセージを出力します。 76 | 77 | ## 外部リンク 78 | 79 | - [Defining Permissions | Android Developers][1] 80 | - [Android アプリのセキュア設計・セキュアコーディングガイド 5.2. Permission と Protection Level][2] 81 | - [App Manifest | Android Developers][3] 82 | - [<permission> | Android Developers][4] 83 | - [<activity> | Android Develpers][5] 84 | - [<activity-alias> | Android Developers][6] 85 | - [<application> | Android Developers][7] 86 | - [<provider> | Android Developers][8] 87 | - [<path-permission> | Android Developers][9] 88 | - [<receiver> | Android Developers][10] 89 | - [<service> | Developers][11] 90 | 91 | 92 | [1]:https://developer.android.com/guide/topics/permissions/defining.html 93 | [2]:http://www.jssec.org/dl/android_securecoding/5_how_to_use_security_functions.html#permission%E3%81%A8protection-level 94 | [3]:https://developer.android.com/guide/topics/manifest/manifest-intro.html 95 | [4]:https://developer.android.com/guide/topics/manifest/permission-element.html 96 | [5]:https://developer.android.com/guide/topics/manifest/activity-element.html 97 | [6]:https://developer.android.com/guide/topics/manifest/activity-alias-element.html 98 | [7]:https://developer.android.com/guide/topics/manifest/application-element.html 99 | [8]:https://developer.android.com/guide/topics/manifest/provider-element.html 100 | [9]:https://developer.android.com/guide/topics/manifest/path-permission-element.html 101 | [10]:https://developer.android.com/guide/topics/manifest/receiver-element.html 102 | [11]:https://developer.android.com/guide/topics/manifest/service-element.html 103 | -------------------------------------------------------------------------------- /JavascriptInterface.md: -------------------------------------------------------------------------------- 1 | # Missing @JavascriptInterface on methods (JavascriptInterface) 2 | 3 | ## 警告されている問題点 4 | 5 | JavaScriptからアクセスするためのルールが守られていないため、スクリプト処理が実行できません。 6 | 7 | ## 対策のポイント 8 | 9 | - JavaScriptから呼び出すメソッドには、@JavascriptInterfaceアノテーションを追加する 10 | 11 | ## 対策の具体例 12 | 13 | JavaのクラスのメソッドをWebView内のJavaScriptから使用したい場合、当該メソッドに@JavascriptInterfaceアノテーションを付記し、WebViewクラスのaddJavascriptInterfaceメソッドで当該クラスのインスタンスを加える必要があります。 14 | セキュリティが強化されたAndroid 4.2(API 17)以降では、@JavascriptInterfaceアノテーションのないメソッドのJavaScriptからの使用はできません。 15 | 16 | ```java 17 | // JavaScript実行用クラス 18 | public class JavaScriptAPI { 19 | @JavascriptInterface 20 | public void methodA(){...} 21 | 22 | // API 17以降では@JavascriptInterfaceのないメソッドはJavaScriptから実行できない 23 | public void methodB(){...} 24 | } 25 | ``` 26 | 27 | ```java 28 | // Activity内で、WebViewインスタンスを生成 29 | WebView webView = new WebView(context); 30 | webView.getSettings().setJavaScriptEnabled(true); // WebViewでのJavaScript実行を有効化 31 | 32 | webView.addJavascriptInterface(new JavaScriptAPI(),"XXX"); // "XXX"はJavaScriptから参照するオブジェクト名 33 | 34 | webView.loadUrl("file:///android_asset/test.html"); 35 | ``` 36 | 37 | ``` 38 | // test.htmlからの使用例 39 | 40 | ``` 41 | 42 | ## 不適切な例 43 | 44 | WebView#addJavascriptInterfaceJavaScriptメソッドに登録するオブジェクト(クラス)に1つも@JavascriptInterfaceアノテーションが付いていない場合、メソッドの実行時にエラーとなります。 45 | 46 | ```java 47 | // @JavascriptInterfaceアノテーションを持たないJavaScript実行用クラス 48 | public class JavaScriptBadAPI { 49 | public void methodA(){...} 50 | 51 | public void methodB(){...} 52 | } 53 | ``` 54 | 55 | ```java 56 | // Activity内で、WebViewインスタンスを生成 57 | WebView webView = new WebView(context); 58 | webView.getSettings().setJavaScriptEnabled(true); 59 | 60 | // @JavascriptInterfaceアノテーションを持たないインスタンスを設定 61 | webView.addJavascriptInterface(new JavaScriptBadAPI(),"XXX"); 62 | 63 | webView.loadUrl("file:///android_asset/test.html"); 64 | ``` 65 | 66 | Lintは、minSdkVersionが17以上でaddJavascriptInterfaceメソッドの対象が@JavascriptInterfaceアノテーションを一つも持っていないことを検知すると、次のようなメッセージを出力します。 67 | 68 | - Lint出力(Error) 69 | "None of the methods in the added interface(<クラス名>) have been annotated with '@android.webkit.JavascriptInterface'; they will not be visible in API 17" 70 | 71 | 注意: targetSdkVersionを17未満に設定するとアノテーションがないメソッドも使用可能になりますが、よりリスクの高い状況になります。詳しくは[addJavascriptInterfaceCalled (AddJavascriptInterface)][AddJavascriptInterface]の項を参照してください。 72 | 73 | ## 外部リンク 74 | 75 | - [Android 4.2 APIs | Android Developers][1] 76 | - [Building Web Apps in WebView | Android Developers][2] 77 | - [WebView | Android Developers][3] 78 | - [Androidアプリのセキュア設計・セキュアコーディングガイド 4.9.3.1. Android4.2未満の端末におけるaddJavascriptInterface()に起因する脆弱性について][4] 79 | 80 | 81 | [AddJavascriptInterface]: AddJavascriptInterface.md 82 | 83 | [1]: https://developer.android.com/about/versions/android-4.2.html 84 | [2]: https://developer.android.com/guide/webapps/webview.html#BindingJavaScript 85 | [3]: https://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface 86 | [4]: http://www.jssec.org/dl/android_securecoding/4_using_technology_in_a_safe_way.html#android-4_x2e2%E6%9C%AA%E6%BA%80%E3%81%AE%E7%AB%AF%E6%9C%AB%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8Baddjavascriptinterface_x28_x29%E3%81%AB%E8%B5%B7%E5%9B%A0%E3%81%99%E3%82%8B%E8%84%86%E5%BC%B1%E6%80%A7%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6 -------------------------------------------------------------------------------- /PackageManagerGetSignatures.md: -------------------------------------------------------------------------------- 1 | # Potential Multiple Certificate Exploit (PackageManagerGetSignatures) 2 | 3 | ## 警告されている問題点 4 | 5 | アプリパッケージを署名した証明書(以下、「アプリ証明書」と称す)の検証方法を間違えた場合、不正なアプリに重要な情報や機能を利用されてしまうリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - 対象のAPKが持つすべてのアプリ証明書を確認する 10 | 11 | ## 対策の具体例 12 | 13 | APKに含まれるアプリ証明書を取得し、利用する際は次のことに気をつける必要があります。 14 | Android 4.4(API 19)以前の端末では、インストール時のアプリ証明書の検証方法に脆弱性がある([FakeID][7])ため、アプリのなりすましが可能です。 15 | 同一端末の他アプリからの呼び出しがなりすましされていないかを確認する場合、下の例のようにAPKに含まれる「すべての」アプリ証明書を確認し、疑わしいものが含まれないことを検査する必要があります。 16 | 17 | ```java 18 | package com.example.checksignature; 19 | 20 | import android.app.Activity; 21 | import android.content.pm.PackageInfo; 22 | import android.content.pm.PackageManager; 23 | import android.content.pm.Signature; 24 | import android.os.Bundle; 25 | import java.security.MessageDigest; 26 | import java.security.NoSuchAlgorithmException; 27 | import java.util.Arrays; 28 | 29 | public class myActivity extends Activity { 30 | private Signature[] sigs = null; 31 | // ホワイトリストに登録した証明書のメッセージダイジェストのみを持つアプリを許可する 32 | // 証明書は開発元から入手する 33 | private static final String[] sigWhiteList = { 34 | "3A544EC58814727C3C424DFD2ECF2F8C7FBE783E11C020649AAE969594485019", 35 | "9A291DF4BC470525B824240ED9EF81C6D6FDEEA3052EFD9FC5A5D7014D98E869"}; 36 | 37 | private boolean getSignatures(String pname) { 38 | PackageInfo pinfo = null; 39 | try { 40 | // 引数で使用しているGET_SIGNATURESはAPI28で非推奨となり、 41 | // 代わりにGET_SIGNING_CERTIFICATESが追加されています 42 | pinfo = getPackageManager().getPackageInfo(pname, PackageManager.GET_SIGNATURES); 43 | } catch (PackageManager.NameNotFoundException e) { 44 | android.util.Log.e("myActivity", "Could not get package info."); 45 | return false; 46 | } 47 | sigs = pinfo.signatures; 48 | return true; 49 | } 50 | 51 | private String byte2hex(byte[] dat) { 52 | if (dat == null) return null; 53 | final StringBuilder hexdec = new StringBuilder(); 54 | for (final byte b : dat) { 55 | hexdec.append(String.format("%02X", b)); 56 | } 57 | return hexdec.toString(); 58 | } 59 | 60 | // パッケージを署名したすべての証明書を検査する 61 | private boolean checkSignatures(String packagename) { 62 | if (!getSignatures(packagename)) return false; 63 | MessageDigest digest = null; 64 | try { 65 | digest = MessageDigest.getInstance("SHA-256"); 66 | } catch (NoSuchAlgorithmException e) { 67 | return false; 68 | } 69 | 70 | for (Signature sig : sigs) { 71 | // アプリ証明書をメッセージダイジェスト化して比較 72 | byte[] sha256 = digest.digest(sig.toByteArray()); 73 | if(!Arrays.asList(sigWhiteList).contains(byte2hex(sha256))) return false; 74 | } 75 | return true; 76 | } 77 | 78 | @Override 79 | protected void onCreate(Bundle savedInstanceState) { 80 | super.onCreate(savedInstanceState); 81 | setContentView(R.layout.activity_main); 82 | 83 | String caller = getCallingActivity().getPackageName(); 84 | // 呼び出し元のアプリ証明書を検査する 85 | if (!checkSignatures(caller)) { 86 | android.util.Log.e("getSig", "Caller is not my partner: " + caller); 87 | finish(); 88 | return; 89 | } 90 | // 以下利用元の確認が出来た時の処理を行う 91 | ... 92 | } 93 | } 94 | ``` 95 | 96 | ただし、Lintはアプリ証明書の取得自体に対して警告を発しているため、上記対応を実施しても警告は継続します。 97 | 98 | note: 自社開発のアプリの連携であれば、signatureレベルのパーミッションを定義・利用することでアプリの身元確認を代用できます。ただし、第三者アプリに対して広く連携する場合も含めて、受信Intentの安全性は常に確認すべきです。 99 | 100 | ## 不適切な例 101 | 102 | 以下の実装は、「対策の具体例」のcheckSignaturesメソッドをホワイトリストの証明書がひとつでも含まれていれば問題なしと判断するように処理しています。 103 | Android 5.0(API 21)以降の端末のみを対象とするのであれば十分ですが、Android 4.4以前の端末では不十分となります。 104 | 105 | ```java 106 | private boolean checkSignatures(String packagename) { 107 | if (!getSignatures(packagename)) return false; 108 | MessageDigest digest = null; 109 | try { 110 | digest = MessageDigest.getInstance("SHA-256"); 111 | } catch (NoSuchAlgorithmException e) { 112 | return false; 113 | } 114 | 115 | for (Signature sig : sigs) { 116 | // アプリ証明書をメッセージダイジェスト化して比較 117 | byte[] sha256 = digest.digest(sig.toByteArray()); 118 | if(Arrays.asList(sigWhiteList).contains(byte2hex(sha256))) return true; 119 | } 120 | return false; 121 | } 122 | ``` 123 | 124 | 125 | Lintは、android.content.pm.PackageManagerのgetPackageInfoメソッドの第2引数にPackageManager.GET_SIGNATURESが含まれていることを検知すると、その戻り値の用途には依らず次のようなメッセージを出力します。 126 | 127 | - Lint出力(Information) 128 | "Reading app signatures from getPackageInfo: The app signatures could be exploited if not validated properly; see issue explanation for details." 129 | 130 | ## 外部リンク 131 | 132 | - [PackageManager | Android Developers][1] 133 | - [PackageInfo | Android Developers][2] 134 | - [Signature | Android Developers][3] 135 | - [MessageDigest | Android Developers][4] 136 | - [FakeID に関する情報1][5] 137 | - [FakeID に関する情報2][6] 138 | - [Black Hat 2014 における FakeID についての発表スライド][7] 139 | - [Android アプリのセキュア設計・セキュアコーディングガイド 4.1.1.3. パートナー限定Activity を作る・利用する][8] 140 | 141 | [1]:https://developer.android.com/reference/android/content/pm/PackageManager.html 142 | [2]:https://developer.android.com/reference/android/content/pm/PackageInfo.html 143 | [3]:https://developer.android.com/reference/android/content/pm/Signature.html 144 | [4]:https://developer.android.com/reference/java/security/MessageDigest.html 145 | [5]:http://blog.trendmicro.co.jp/archives/9642 146 | [6]:https://www.androidcentral.com/fake-id-and-android-security-updated 147 | [7]:https://www.blackhat.com/docs/us-14/materials/us-14-Forristal-Android-FakeID-Vulnerability-Walkthrough.pdf 148 | [8]:http://www.jssec.org/dl/android_securecoding/4_using_technology_in_a_safe_way.html#%E3%83%91%E3%83%BC%E3%83%88%E3%83%8A%E3%83%BC%E9%99%90%E5%AE%9Aactivity%E3%82%92%E4%BD%9C%E3%82%8B%E3%83%BB%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B 149 | 150 | -------------------------------------------------------------------------------- /PackagedPrivateKey.md: -------------------------------------------------------------------------------- 1 | # Packaged private key (PackagedPrivateKey) 2 | 3 | ## 警告されている問題点 4 | 5 | アプリケーションパッケージ(APK)に秘密鍵を格納すると、それを悪意あるユーザーやマルウェアによって取り出され、秘密鍵で署名した情報が改竄されたり、なりすましのリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - アプリのAPK(ソースコードやリソースなど)に秘密鍵を格納しない 10 | 11 | ## 対策の具体例 12 | 13 | 秘密鍵をAPKで保持しなければならない設計には問題があると考えられます。アプリやサービスの仕様・設計を見直してください。 14 | 万一、秘密鍵のAPKへの埋め込みが必要な場合は、セキュア設計の専門家に相談してください。 15 | 16 | ## 不適切な例 17 | 18 | 秘密鍵をアセット(assets)やリソース(res)ディレクトリに配置したり、あるいはソースコードに直接埋め込むことができます。 19 | Lintは、このうちassetsとresディレクトリに配置された秘密鍵(らしいと思われる)以下のファイルを検知します。 20 | 21 | - ファイル名が.pemまたは.keyで終わる 22 | - 最初の行が “—”で開始され、“PRIVATE KEY”という文字列を含んでいる 23 | 24 | Lintは、assetsあるいはresディレクトリに上で述べた条件に合致するファイルを検知すると、次のようなメッセージを出力します。 25 | 26 | - Lintの主力結果(Error) 27 | "The \`(filename)\` file seems to be a private key file. Please make sure not to embed this in your APK file." 28 | 29 | ソースコードに埋め込まれた秘密鍵についてはメッセージを出力しませんが、リバースエンジニアリングを用いて秘密鍵を取り出すことは可能なので、同様のリスクがあります。 30 | また、Lintの検知条件に合致しないように秘密鍵を格納しても、攻撃者が解析する際の妨げにはなりません。 31 | 32 | -------------------------------------------------------------------------------- /SSLCertificateSocketFactoryCreateSocket.md: -------------------------------------------------------------------------------- 1 | # Insecure call to SSLCertificateSocketFactory.createSocket() (SSLCertificateSocketFactoryCreateSocket) 2 | 3 | ## 警告されている問題点 4 | 5 | 暗号化通信においてホスト名の検証をしていないため、中間者攻撃[^1]を受けるリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - 接続先のサーバー証明書のホスト名検証で、接続先の正当性を検証する 10 | 11 | ## 対策の具体例 12 | 13 | SSL/TLSによる通信では、サーバー証明書とホスト名を合わせて検証しなければ、接続先を正しく検証することができません。 14 | SSLCertificateSocketFactoryクラスのcreateSocketメソッドが生成するSocketはホスト名指定とIPアドレス指定の2種類がありますが、接続後の署名検査に加えて、証明書のホスト名検証も行われるホスト名指定の方を使用してください。 15 | 16 | ```java 17 | import java.io.IOException; 18 | import javax.net.ssl.SSLSocket; 19 | import android.app.Activity; 20 | import android.os.Bundle; 21 | import android.net.SSLCertificateSocketFactory; 22 | 23 | public class MyApp extends Activity { 24 | 25 | private SSLSocket sock = null; 26 | 27 | public boolean connectToHost (String host, int port) { 28 | SSLCertificateSocketFactory sf = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(0); 29 | 30 | try { 31 | // ホスト名を指定して socket を作成すると証明書のホスト名検証も実施してくれる 32 | sock = (SSLSocket) sf.createSocket(host, port); 33 | } catch (IOException e) { 34 | android.util.Log.e("MyApp", e.getMessage()); 35 | return false; 36 | } 37 | android.util.Log.d("MyApp", "Success creating socket"); 38 | return true; 39 | } 40 | } 41 | ``` 42 | 43 | ## 不適切な例 44 | 45 | デバッグや開発中のホスト名検証を省略するためにIPアドレス指定のcreateSocketメソッドを使用すると、そのままリリースされるリスクがあります。 46 | Android 7.0(API 24)以降では[「Network Security Configuration」][3]を利用できるので、そちらも参考にしてください。 47 | 48 | 49 | ```java 50 | import java.io.IOException; 51 | import javax.net.ssl.SSLSocket; 52 | import java.net.InetAddress; 53 | import android.app.Activity; 54 | import android.os.Bundle; 55 | import android.net.SSLCertificateSocketFactory; 56 | 57 | public class MyApp extends Activity { 58 | 59 | private SSLSocket sock = null; 60 | 61 | public boolean connectToHost (InetAddress inet, int port) { 62 | SSLCertificateSocketFactory sf = (SSLCertificateSocketFactory) SSLCertificateSocketFactory.getDefault(0); 63 | 64 | try { 65 | // IPアドレスを指定して socket を作成すると証明書のホスト名検証は実施されない 66 | sock = (SSLSocket) sf.createSocket(inet, port); 67 | } catch (IOException e) { 68 | android.util.Log.e("MyApp", e.getMessage()); 69 | return false; 70 | } 71 | android.util.Log.d("MyApp", "Success creating socket"); 72 | 73 | return true; 74 | } 75 | } 76 | ``` 77 | 78 | Lintは、上のようにSSLCertificateSocketFactory.createSocket()がInetAddressを引数とする呼び出しを検出すると、次のようなメッセージを出力します。 79 | 80 | - Lint出力(Warning) 81 | "Use of‘SSLCertificateSocketFactory.createSocket()’ with an InetAddress parameter can cause insecure network traffic due to trusting arbitrary hostnames in TLS/SSL certificates presented by peers." 82 | 83 | ## 外部リンク 84 | 85 | - [SSLCertificateSocketFactory | Android Developers][1] 86 | - [Transport Layer Security | Wiki Pedia][2] 87 | 88 | [1]:https://developer.android.com/reference/android/net/SSLCertificateSocketFactory.html 89 | [2]:https://ja.wikipedia.org/wiki/Transport_Layer_Security 90 | [3]: https://developer.android.com/training/articles/security-config.html 91 | 92 | [^1]: dummy "中間者攻撃:通信している2人のユーザーの間に第三者が介在し、送信者と受信者の両方になりすまして、ユーザーが気付かないうちに通信を盗聴したり、制御したりすること" 93 | -------------------------------------------------------------------------------- /SSLCertificateSocketFactoryGetInsecure.md: -------------------------------------------------------------------------------- 1 | # Call to SSLCertificateSocketFactory.getInsecure() (SSLCertificateSocketFactoryGetInsecure) 2 | 3 | ## 警告されている問題点 4 | 5 | 暗号化通信においてホスト名の検証をできないSocketを使用しているため、中間者攻撃[^1]を受けるリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - 接続先のサーバー証明書のホスト名検証で、接続先の正当性を検証する 10 | 11 | ## 対策の具体例 12 | 13 | 接続先の正当性検証は相当の専門知識を必要としますので、自作せずに既存の仕組みを正しく利用するようにしてください。 14 | 15 | ### HttpsURLConnectionクラスを使用する 16 | 17 | HttpsURLConnectionクラスはデフォルトでセキュリティチェックが有効なSocketFactoryおよびSocketを使用しているので、安全な通信が可能になります。 18 | 19 | ```java 20 | import javax.net.ssl.HttpsURLConnection; 21 | 22 | public class SSLCertificateSocketFactoryExample { 23 | public void connect() { 24 | try { 25 | URL url = new URL("https://example.com/"); 26 | HttpsURLConnection conn = (HttpsURLConnection)url.openConnection(); 27 | } catch (...) { 28 | : 29 | } 30 | } 31 | } 32 | ``` 33 | 34 | ### セキュリティチェックが有効なSSLCertificateSocketFactoryを使用する 35 | 36 | SSLSocketを直接生成する場合は、getDefaultメソッドによって取得されるSSLCertificateSocketFactoryを使用してください。 37 | getDefaultメソッドで得られるセキュリティチェックが有効なインスタンスは、安全なSocketを生成できます。 38 | 39 | ```java 40 | import android.net.SSLCertificateSocketFactory; 41 | 42 | public class SSLCertificateSocketFactoryExample { 43 | public void connect() { 44 | SSLCertificateSocketFactory sf = (SSLCertificateSocketFactory)SSLCertificateSocketFactory.getDefault(0); 45 | 46 | try { 47 | sf.createSocket("example.com", 443); 48 | : 49 | } catch (...) { 50 | : 51 | } 52 | } 53 | } 54 | ``` 55 | 56 | ただし、createSocketの引数にホスト名ではなく接続先InetAddress(IPアドレス)を指定すると、ホスト名の検証を行わない安全ではないSocketが生成されるので注意してください。 57 | これについての詳細は [Insecure call to SSLCertificateSocketFactory.createSocket()][4]の項を参照してください。 58 | 59 | ## 不適切な例 60 | 61 | 下の例のようにgetInsecureメソッドで取得したセキュリティチェックが無効なSocketFactoryを使用すると、証明書の検証を行わなくなるため正しく接続先を確認できません。 62 | 63 | ```java 64 | import android.net.SSLCertificateSocketFactory; 65 | import javax.net.ssl.HttpsURLConnection; 66 | 67 | public class SSLCertificateSocketFactoryExample { 68 | public void connect() { 69 | HttpsURLConnection.setDefaultSSLSocketFactory(SSLCertificateSocketFactory.getInsecure(0,null)); 70 | try { 71 | URL url = new URL("https://example.com/"); 72 | HttpsURLConnection conn = (HttpsURLConnection)url.openConnection(); 73 | : 74 | } catch (...) { 75 | : 76 | } 77 | } 78 | } 79 | ``` 80 | 81 | デバッグ時など、事情により正式なサーバーを用いたHTTPS接続ができずにセキュリティチェックを無効とすることがありますが、リリース後にその実装が残る危険があります。 82 | Android 7.0(API 24)以降では[Network Security Configuration][2]を利用できるので、そちらも参考にしてください。 83 | 84 | Lintは、SSLCertificateSocketFactoryクラスのgetInsecureメソッドの呼び出しを検知すると、次のようなメッセージを出力します。 85 | 86 | - Lint出力(Warning) 87 | "Use of SSLCertificateSocketFactory.getInsecure() can cause insecure network traffic due to trusting arbitrary TLS/SSL certificates presented by peers." 88 | 89 | ## 外部リンク 90 | 91 | - [SSLCertificateSocketFactory | Android Developers][1] 92 | - [ネットワークセキュリティ構成 | Android Developers][2] 93 | - [Security with HTTPS and SSL | Android Developers][3] 94 | 95 | [1]:https://developer.android.com/reference/android/net/SSLCertificateSocketFactory.html 96 | [2]:https://developer.android.com/training/articles/security-config.html 97 | [3]:https://developer.android.com/training/articles/security-ssl.html 98 | [4]:SSLCertificateSocketFactoryCreateSocket.md 99 | 100 | 101 | [^1]: dummy "中間者攻撃:通信している2人のユーザーの間に第三者が介在し、送信者と受信者の両方になりすまして、ユーザーが気付かないうちに通信を盗聴したり、制御したりすること" -------------------------------------------------------------------------------- /SecureRandom.md: -------------------------------------------------------------------------------- 1 | # Using a fixed seed with SecureRandom (SecureRandom) 2 | 3 | ## 警告されている問題点 4 | 5 | 疑似乱数生成器(SecureRandom)のシードに不適切な値を使用しているため、乱数の生成が予測される可能性が高くなります。 6 | 7 | ## 対策のポイント 8 | 9 | - SecureRandomに不適切なシードを設定しない 10 | 11 | ## 対策の具体例 12 | 13 | ### シードを設定しない 14 | 15 | デフォルトで推測困難なシードが設定されるため、特別な理由がない限りSecureRandomにシードを設定する必要はありません。 16 | コンストラクタでシードを設定せず、setSeedメソッドも使用しないでください。 17 | 18 | ```java 19 | // 引数のないコンストラクタを使用する 20 | Random r = new SecureRandom(); 21 | 22 | // r.setSeed()を使用しない 23 | ... 24 | byte bytes[] = new byte[16]; 25 | r.nextBytes(bytes); // 乱数のバイト列を取得 26 | ``` 27 | 28 | Note: Android 8.0 (API 26)以降ではシードに依らず乱数を生成するため、setSeedメソッドが従来通りに機能しません。 29 | 30 | ## 不適切な例 31 | 32 | ### SecureRandomのコンストラクタで定数や時刻のシードを設定する 33 | 34 | 下の例のように、コンストラクタにバイト列を渡してシードを設定すると、予測可能な乱数が生成されることになります。 35 | 36 | ```java 37 | Random r = new SecureRandom(new byte[] { 1, 2, 3} ); // 毎回同じ乱数が生成される 38 | ``` 39 | 40 | ```java 41 | Random r = new SecureRandom(System.currentTimeMillis()); // 時刻を利用していると予測されると容易にシードが推定される 42 | ``` 43 | 44 | ただし、Lintはコンストラクタでの不適切なシードの設定を検知することができません。 45 | 46 | ### setSeedメソッドで定数や時刻のシードを設定する 47 | 48 | setSeedメソッドで定数や時刻をシードに設定した場合も、生成される乱数の性質は上記の例と同様になります。 49 | 定数値のシードは常に同じ擬似乱数列を生成し、時刻のシードは容易に推測が可能です。 50 | 51 | ```java 52 | Random r = new SecureRandom(); 53 | 54 | // 定数のシードを与えている 55 | r.setSeed(new byte[] { 56 | 0x04, 0xFD, 0xA8, 0x36, 0x9A, 0x75, 0x0A, 0xEC, 57 | 0x77, 0x1B, 0x8A, 0x64, 0x3D, 0x19, 0xDE, 0xAD, 58 | 0xA2, 0xF9, 0x66, 0x64, 0x0A, 0x3B, 0xBE, 0xEF, 59 | 0x6E, 0x69, 0x42, 0x33, 0x0A, 0x91, 0xF7, 0x57 60 | }); 61 | ``` 62 | 63 | ```java 64 | Random r = new SecureRandom(); 65 | 66 | // 現在時刻 (ミリ秒単位) をシードに与えている 67 | r.setSeed(System.currentTimeMillis()); 68 | ``` 69 | 70 | Lintは、前者の例のようにシードに定数値の設定を検知すると、次のようなメッセージを出力します。 71 | 72 | - Lint出力(Warning) 73 | " Do not call \`setSeed()\` on a \`SecureRandom\` with a fixed seed: it is not secure. Use \`getSeed()\`." 74 | ただし、クラス定数やインスタンス定数をシードに設定した場合には検知できません。 75 | 76 | Lintは、後者の例のようにシードに現在時刻の設定を検知すると、次のようなメッセージを出力します。 77 | 78 | - Lint出力(Warning) 79 | "It is dangerous to seed \`SecureRandom\` with the current time because that value is more predictable to an attacker than the default seed." 80 | System.nanoTime()をシードに設定した場合も同様に検知します。 81 | 82 | ## 外部リンク 83 | 84 | - [SecureRandom | Android Developers][1] 85 | - [MSC63-J. Ensure that SecureRandom is properly seeded][2] 86 | - [RFC 4086: Randomness Requirements for Security][3] 87 | - [NIST SP 800-22 Rev. 1a][4] 88 | 89 | 90 | [1]:https://developer.android.com/reference/java/security/SecureRandom.html 91 | [2]:https://www.securecoding.cert.org/confluence/display/java/MSC63-J.+Ensure+that+SecureRandom+is+properly+seeded 92 | [3]:https://tools.ietf.org/html/rfc4086 93 | [4]:https://csrc.nist.gov/publications/detail/sp/800-22/rev-1a/final 94 | 95 | -------------------------------------------------------------------------------- /SetJavascriptEnabled.md: -------------------------------------------------------------------------------- 1 | # Using setJavaScriptEnabled (SetJavascriptEnabled) 2 | 3 | ## 警告されている問題点 4 | 5 | WebViewのJavaScriptを有効にしているため、クロスサイトスクリプティングによる攻撃を受けるリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | 以下のいずれかの対策を実施してください。 10 | 11 | - ロードするリソースを信頼できるものに限定する 12 | - JavaScriptを無効にする 13 | 14 | ## 対策の具体例 15 | 16 | JavaScriptを有効にしていると[addJavascriptInterface Called (AddJavascriptInterface)][7]に記載している脆弱性の影響を受ける可能性がありますので、そちらも参照してください。 17 | 18 | ### リソースを限定する 19 | 20 | JavaScriptを有効にしたWebViewを使う場合は、接続先を信頼できるサイトに限定することが重要です。 21 | 不用意なリソースをロードしないようにアプリを設計すると共に、ロードするリソースに不正なリンクなどを含まないようにしてください。 22 | 23 | ```java 24 | WebView webView = new WebView(context); 25 | webView.getSettings().setJavaScriptEnabled(true); 26 | 27 | webView.loadUrl("https://trustworthy.example.com"); 28 | ``` 29 | 30 | リソースのロードを柔軟に制御するshouldOverrideUrlLoadingメソッドを用いたサンプルが[addJavascriptInterface Called (AddJavascriptInterface)][7]にありますので、あわせて参照してください。 31 | 32 | 注意: Lintは、JavaScriptを有効(`setJavaScriptEnabled(true);`)にしていることだけを検知して警告メッセージを出力しますので、ロードするリソースを如何に制限しようとメッセージは出力され続けます。クロスサイトスクリプティング(XSS)を懸念してのことですが、XSSの対策については[「OWASP クロスサイトスクリプティング対策チートシート」][6]を参照してください。 33 | 34 | 接続先を完全に信頼できるサイトに限定することが出来ない場合は、Android 5.0(API 21)以降で使えるWebViewのSafe Browsing[^注釈2]設定を有効にすることで、Googleが管理するブラックリストに含まれるサイトへのアクセスを抑制できます。 35 | 詳細は[「What is Safe Browsing?」][4]、アプリでURLの個別検査が必要な場合は[「SafetyNet Safe Browsing API」][5]も参照してください。 36 | 37 | ``` 38 | 39 | 40 | // Googleが提供するSafe Browsingを有効化 41 | 43 | ... 44 | 45 | 46 | ``` 47 | 48 | Android 7.0(API 24)以降ではNetwork Security Configurationの機能を使う方法もあります。この機能は、宣言型設定ファイルを使用してネットワークセキュリティの設定をカスタマイズします。 49 | 50 | まず、マニフェストに設定ファイルの場所を記載します。 51 | 52 | ``` 53 | 54 | ... 55 | 56 | // ネットワークセキュリティ設定を res/xml/network_security_config.xml に記述することを宣言 57 | 59 | ... 60 | 61 | ``` 62 | 63 | これでnetwork_security_config.xmlに信用する認証局を指定できるようになります。 64 | 他にも、デバッグ用の接続先、平文通信の抑制、特定の証明書の強化を設定することができます。 65 | 詳しくは[Android DevelopersのAPIガイド][8]を参照してください。 66 | 67 | 以下に、平文通信を抑制するときの例を示します。 68 | domain-configタグのcleartextTrafficPermitted属性をfalseにすることで実現できます。 69 | ただし、この設定をしてもAndroid 7.0(API 24)ではWebViewからの平文通信は可能で、Android 8.0(API 26)以降で接続方法に依らず設定が有効となります。 70 | 71 | ``` 72 | 73 | 74 | 75 | example.com 76 | 77 | 78 | : 79 | ``` 80 | 81 | ### JavaScriptを無効にする 82 | 83 | 信頼できないリソースにアクセスする可能性のある場合には、JavaScriptを無効にすることを強く推奨します。 84 | Android 8.0(API 26)までのWebViewのデフォルトは「無効」ですが、`setJavaScriptEnabled(false);`で明示的にJavaScriptを無効にしておくことを推奨します。 85 | 86 | ```java 87 | import android.app.Activity; 88 | import android.os.Bundle; 89 | import android.webkit.WebView; 90 | 91 | public class MyActivity extends Activity { 92 | 93 | private WebView webView; 94 | 95 | @Override 96 | public void onCreate(Bundle savedInstanceState) { 97 | super.onCreate(savedInstanceState); 98 | setContentView(R.layout.main); 99 | WebView webView = (WebView)findViewById(R.id.webView); 100 | 101 | // JavaScriptが不要な場合は明示的に無効にする 102 | webView.getSettings().setJavaScriptEnabled(false); 103 | 104 | webView.loadUrl("https://unknown.example.com/"); 105 | } 106 | } 107 | ``` 108 | 109 | 110 | ## 不適切な例 111 | 112 | 設計上、JavaScriptを使用しないにもかかわらず、これを有効にすることは余計なリスクを抱えることになります。 113 | 114 | ```java 115 | import android.app.Activity; 116 | import android.os.Bundle; 117 | import android.webkit.WebView; 118 | 119 | public class SetJavaScriptEnabled extends Activity { 120 | 121 | @Override 122 | public void onCreate(Bundle savedInstanceState) { 123 | super.onCreate(savedInstanceState); 124 | setContentView(R.layout.main); 125 | WebView webView = (WebView)findViewById(R.id.webView); 126 | 127 | // webViewでJavaScriptを有効にする 128 | webView.getSettings().setJavaScriptEnabled(true); 129 | 130 | webView.loadUrl("https://example.com/"); 131 | } 132 | } 133 | ``` 134 | 135 | Lintは、 `setJavaScriptEnabled(true)` という形のメソッド呼び出しを検知すると、次のようなメッセージを出力します: 136 | 137 | - Lint出力(Warning) 138 | “Using setJavaScriptEnabled can introduce XSS vulnerabilities into your application, review carefully.” 139 | 140 | ## 外部リンク 141 | 142 | - [WebView | Android Developers][1] 143 | - [WebView を使用する上でのセキュリティ対策情報][2] 144 | - [Androidアプリのセキュア設計・セキュアコーディングガイド][3] 145 | - [What is Safe Browsing?][4] 146 | - [SafetyNet Safe Browsing API][5] 147 | - [OWASP クロスサイトスクリプティング (XSS) 対策チートシート][6] 148 | 149 | 150 | [1]:https://developer.android.com/reference/android/webkit/WebView.html 151 | [2]:https://developer.android.com/training/articles/security-tips.html#WebView 152 | [3]:http://www.jssec.org/dl/android_securecoding/ 153 | [4]:https://developers.google.com/safe-browsing/ 154 | [5]:https://developer.android.com/training/safetynet/safebrowsing.html 155 | [6]:https://jpcertcc.github.io/OWASPdocuments/CheatSheets/XSSPrevention.html 156 | [7]:AddJavascriptInterface.md 157 | [8]:https://developer.android.com/training/articles/security-config.html 158 | 159 | 160 | [^注釈1]: javascript:void(0); "接続先サーバーの証明書や公開鍵をアプリ内にあらかじめ保持しておき、接続先のサーバーをアプリ内で保持しているものに限定する機能。" 161 | 162 | [^注釈2]: javascript:void(0); "Safe Browsing:Googleが安全でないと判断したサイトにユーザーがアクセスしようとしたときに警告を出す、Googoleが提供するサービス。" -------------------------------------------------------------------------------- /SetWorldReadable.md: -------------------------------------------------------------------------------- 1 | # File.setReadable() used to make file world-readable (SetWorldReadable) 2 | 3 | ## 警告されている問題点 4 | 5 | ファイルを任意のアプリから読める設定にしているため、重要な情報が漏洩するリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - アプリ利用のファイルはアプリディレクトリ[^注釈1]内に非公開で作成する 10 | 11 | ## 対策の具体例 12 | 13 | Context.openFileOutputメソッドでのファイル作成時にモードをMODE_PRIVATEに指定することで、他のアプリに公開しないファイルを作成することが出来ます。原則、ファイル作成後はアクセス制御を変更しないようにしてください。 14 | 外付けのストレージでは、ファイルのアクセス制御をアプリ側で行うことができないため、重要な情報の保存場所にしないようにしてください。 15 | 16 | ```java 17 | try { 18 | // ファイルをアプリディレクトリ内に非公開で作成する 19 | fileout = openFileOutput(MYFILE, MODE_PRIVATE); 20 | } catch (IOException e) { 21 | android.util.Log.e("MyApp", "Failed to create file."); 22 | return; 23 | } 24 | ``` 25 | 26 | 注意: 以前はMODE_WORLD_READABLE、MODE_WORLD_WRITEABLEというモードも使用できましたが、Android 4.2(API 17)で非推奨となり、Android 7.0(API 24)以降の端末では、これらのモード指定では機能しなくなりました。 27 | 28 | Note: 特定のアプリに対して情報を共有するには、ContentProvider、BroadcastReceiver、およびServiceを利用してください。[Sharing Files][4]に関する情報も参考にしてください。 29 | 30 | 31 | ## 不適切な例 32 | 33 | 以下の例では一時的に読み込みを許可するつもりで実装していますが、意図している通りに動作しません。 34 | さらに、読み込みを許可した後、例外が発生するなどして戻せない場合のことを考慮すると、このような仕様は避けるべきです。 35 | 36 | ```java 37 | public void extendReadPermission(File f) { 38 | try { 39 | // 第一引数(読取り許可)をtrue、第二引数(所有者のみ適用)をfalseにすることで、すべての読取りを許可する 40 | if (!f.setReadable(true, false)) { 41 | (省略) 42 | } 43 | 44 | // 第一引数(読取り許可)をtrue、第二引数(所有者のみ適用)をtrueにすることで、所有者のみ読取りを許可する 45 | if (!f.setReadable(true, true)) { 46 | // この場合、setReadable(true, true)だけだと所有者以外の読取り許可が残ってしまいます 47 | // setReadable(false, false)の実行後にsetReadable(true, true)とする必要があります 48 | } 49 | 50 | } catch (SecurityException e) { 51 | (省略) 52 | } 53 | } 54 | ``` 55 | 56 | Lintは上の例のようにsetReadable(true, false)という形のメソッド呼び出しを検知すると、次のようなメッセージを出力します。 57 | 58 | - Lint出力(Warning) 59 | "Setting file permission to world-readable can be risky, review carefully." 60 | 61 | ## 外部リンク 62 | 63 | - [File | Android Developers][1] 64 | - [Context | Android Developers][2] 65 | - [Androidアプリのセキュア設計・セキュアコーディングガイド 4.6.ファイルを扱う][3] 66 | - [Sharing Files | Android Developers][4] 67 | 68 | [1]:https://developer.android.com/reference/java/io/File.html 69 | [2]:https://developer.android.com/reference/android/content/Context.html 70 | [3]:https://www.jssec.org/dl/android_securecoding/4_using_technology_in_a_safe_way.html#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E6%89%B1%E3%81%86 71 | [4]:https://developer.android.com/training/secure-file-sharing/index.html 72 | 73 | 74 | [^注釈1]: javascript:void(0); "アプリディレクトリ:アプリの内部メモリ領域。通常、/data/data/<package-name>を指す。" 75 | -------------------------------------------------------------------------------- /SetWorldWritable.md: -------------------------------------------------------------------------------- 1 | # File.setWritable() used to make file world-writable (SetWorldWritable) 2 | 3 | ## 警告されている問題点 4 | 5 | ファイルを任意のアプリから書き込める設定にしているため、重要な情報が改竄されたり、破壊されるリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - アプリ利用のファイルはアプリディレクトリ[^注釈1]内に非公開で作成する 10 | 11 | ## 対策の具体例 12 | 13 | 非公開でファイルを作成する方法は[File.setReadable() used to make file world-readable][5]に同じなのでそちらを参照してください。 14 | 15 | ## 不適切な例 16 | 17 | 以下の例ではファイルに対して他のアプリからの書き込みを許可しているため、情報の安全性を保持することができません。 18 | 19 | ```java 20 | public void setWritePermission(File f) { 21 | try { 22 | // 第一引数(書込み許可)をtrue、第二引数(所有者のみ適用)をfalseにすることで、すべての書き込みを許可する 23 | f.setWritable(true, false); 24 | 25 | (省略) 26 | 27 | } catch (SecurityException e) { 28 | (省略) 29 | } 30 | } 31 | ``` 32 | 33 | Lintは上の例のようにsetWritable(true, false)という形のメソッド呼び出しを検知すると、次のようなメッセージを出力します。 34 | 35 | - Lint出力(Warning) 36 | "Setting file permission to world-writable can be risky, review carefully." 37 | 38 | ## 外部リンク 39 | 40 | - [File | Android Developers][1] 41 | - [Context | Android Developers][2] 42 | - [Androidアプリのセキュア設計・セキュアコーディングガイド 4.6.ファイルを扱う][3] 43 | - [Sharing Files | Android Developers][4] 44 | 45 | [1]:https://developer.android.com/reference/java/io/File.html 46 | [2]:https://developer.android.com/reference/android/content/Context.html 47 | [3]:http://www.jssec.org/dl/android_securecoding/4_using_technology_in_a_safe_way.html#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E6%89%B1%E3%81%86 48 | [4]:https://developer.android.com/training/secure-file-sharing/index.html 49 | [5]:SetWorldReadable.md 50 | 51 | 52 | [^注釈1]: javascript:void(0); "アプリディレクトリ:アプリの内部メモリ領域。通常、/data/data/<package-name>を指す。" 53 | -------------------------------------------------------------------------------- /SignatureOrSystemPermissions.md: -------------------------------------------------------------------------------- 1 | # signatureOrSystem permissions declared (SignatureOrSystemPermissions) 2 | 3 | ## 警告されている問題点 4 | 5 | 通常のアプリには必要としないレベルのパーミッションが要求されているために、過剰な要求として警告が出力されています。 6 | 7 | ## 対策のポイント 8 | 9 | - パーミッションとして適切なレベルを設定する 10 | 11 | ## 対策の具体例 12 | 13 | 以下は、ユーザーの個人情報を参照するなどの重要な情報を取り扱う例です。 14 | READ_CONTACTSのprotection levelは"dangerous"で、パーミッショングループは"PERSONAL_INFO"です。 15 | アプリがDangerousパーミッションを要求するので、Android OSはユーザーに対して確認画面を表示し、そのパーミッションの利用を許可するかどうかの判断を求めます。 16 | つまり、ユーザーの許可なく個人情報にアクセス出来ないように保護をしています。 17 | 18 | ``` 19 | 20 | 21 | 26 | 27 | : 28 | 29 | : 30 | 31 | ``` 32 | 33 | 次は、他社のアプリから利用されては困る機能や情報を取り扱う例です。 34 | この場合、自社独自のsignatureレベルのパーミッションを定義して、同じ秘密鍵で署名したアプリのみがアクセスできるようにします。 35 | 36 | ``` 37 | 38 | 42 | 45 | : 46 | : 47 | 48 | 49 | ``` 50 | 51 | ## 不適切な例 52 | 53 | 下の例では、パーミッションの保護レベルとして通常は使用しない"signatureOrSystem"を指定しています。 54 | 過剰な保護レベルを要求していると判断して、Lintが警告を出力します。 55 | 56 | ``` 57 | 58 | 59 | 63 | 64 | 68 | 71 | 72 | 73 | ``` 74 | 75 | Lintは、`android:protectionLevel="signatureOrSystem"`となっている設定を検知すると、次のようなメッセージを出力します 76 | 77 | - Lint出力(Warning) 78 | "protection level should probably not be set to 'signatureOrSystem'." 79 | 80 | ## 外部リンク 81 | 82 | - [Defining Permissions | Android Developers][1] 83 | - [<permission> | Android Developers][2] 84 | - [Android アプリのセキュア設計・セキュアコーディングガイド 5.2. Permission と Protection Level][3] 85 | 86 | [1]:https://developer.android.com/guide/topics/permissions/defining.html 87 | [2]:https://developer.android.com/guide/topics/manifest/permission-element.html 88 | [3]:http://www.jssec.org/dl/android_securecoding/5_how_to_use_security_functions.html#permission%E3%81%A8protection-level 89 | 90 | 91 | -------------------------------------------------------------------------------- /TrulyRandom.md: -------------------------------------------------------------------------------- 1 | # Weak RNG (TrulyRandom) 2 | 3 | ## 警告されている問題点 4 | 5 | 脆弱性のある標準APIを使用して疑似乱数の生成や暗号化を行っているため、乱数の生成が予測される可能性があります。 6 | 7 | ## 対策のポイント 8 | 9 | - アプリがサポートするAndroidの最小バージョン(minSdkVersion)を上げる 10 | 11 | ## 対策の具体例 12 | 13 | Android 4.4以降の端末では、 [CVE-2013-7372][1], [CVE-2013-7373][2]に関連する脆弱性が修正されているので、Android 4.3以下のバージョンをサポートすべき合理的な理由がない場合には、minSdkVersionを19 (Android 4.4)以上にすることを積極的に行ってください。 14 | 15 | minSdkVersionの変更は、Android Studioで以下のように行います。 16 | 17 | ``` 18 | 1. Tools -> Android -> Android SDK Default Setting 画面でSDKインストール 19 | (指定するバージョンがインストール済なら1.の作業は不要) 20 | 2. File -> Project Structure… 画面から、アプリのFlavorsタグのMin Sdk Versionを変更 21 | ``` 22 | 23 | アプリの仕様や設計上の理由でどうしてもminSdkVersionを上げられない場合は、アプリで対応コードを実装してください。 24 | この場合、SHA1PRNGアルゴリズムを差し替え、予測困難なビット列でシードを再設定する必要がありますが、具体的な方法については [Android Developers Blog - Some SecureRandom Thoughts][5]を参照してください。 25 | 26 | ## 不適切な例 27 | 28 | Android 4.3以下のバージョンで、SecureRandomの他、内部的に擬似乱数を生成する暗号化、鍵生成、鍵ペア生成、鍵共有 (鍵合意)、SSLEngineクラスなどの暗号関連クラスを使用すると暗号学的に安全となりません。 29 | 具体的には下記のメソッド呼び出しあるいはクラスのインスタンス化がLintの検出対象となります。 30 | 31 | - SecureRandom 32 | - Cipher.init(mode, key) ※第一引数のmodeがENCRYPT\_MODE, WRAP\_MODEのいずれかの場合のみ 33 | - Signature.initSign(...) 34 | - KeyGenerator.getInstance(algorithm) 35 | - KeyPairGenerator.getInstance(algorithm) 36 | - KeyAgreement.getInstance(algorithm) 37 | - SSLEngine.wrap, SSLEngine.unwrap 38 | 39 | 以下は、Android 4.3 (API 18)以下をサポートし、Cipherインスタンスで暗号化しています。 40 | 41 | ``` 42 | 43 | 44 | 45 | 46 | ... 47 | 48 | 49 | ``` 50 | 51 | ```java 52 | KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 53 | keyStore.load(null); 54 | 55 | Cipher aes = Cipher.getInstance("AES/CBC/PKCS5Padding"); 56 | final Key key = keyStore.getKey("secret", null); 57 | 58 | aes.init(Cipher.ENCRYPT_MODE, key); 59 | ``` 60 | 61 | Lintは、上の例のようにアプリがAndroid 4.3(API 18)以下をサポートした状態で暗号機能の使用を検知すると、次のようなメッセージを出力します。 62 | 63 | - Lint出力(Warning) 64 | "Potentially insecure random numbers on Android 4.3 and older. Read https://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html for more info." 65 | 66 | ## 外部リンク 67 | 68 | - [CVE-2013-7372][1] 69 | - [CVE-2013-7373][2] 70 | - [Kai Michaelis, Christopher Meyer, and Jörg Schwenk. 2013. Randomly Failed! The State of Randomness in Current Java Implementations. Topics in Cryptology – CT-RSA 2013 Lecture Notes in Computer Science (February 2013), 129–144. DOI][3] 71 | - [Martin Boßlet. 2013. OpenSSL PRNG Is Not (Really) Fork-safe. (August 2013). Retrieved November 20, 2017][4] 72 | - [Android Developers Blog - Some SecureRandom Thoughts][5] 73 | 74 | 75 | [1]:http://www.cvedetails.com/cve/CVE-2013-7372/ 76 | [2]:http://www.cvedetails.com/cve/CVE-2013-7373/ 77 | [3]:http://www.nds.rub.de/media/nds/veroeffentlichungen/2013/03/25/paper_2.pdf 78 | [4]:http://emboss.github.io/blog/2013/08/21/openssl-prng-is-not-really-fork-safe/ 79 | [5]:https://android-developers.googleblog.com/2013/08/some-securerandom-thoughts.html 80 | 81 | 82 | -------------------------------------------------------------------------------- /TrustAllX509TrustManager.md: -------------------------------------------------------------------------------- 1 | # Insecure TLS/SSL trust manager (TrustAllX509TrustManager) 2 | 3 | ## 警告されている問題点 4 | 5 | SSL/TLS証明書検証を適切に行っていないため、HTTPS通信などに対する中間者攻撃[^1]を受けるリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - 証明書検証をしないようにするためにTrustManagerインターフェースを使用しない 10 | 11 | ## 対策の具体例 12 | 13 | 特別な証明書検証ロジックが必要ないならば、サーバーの証明書検証およびホスト名検証を行ってくれる既存の方法を利用してください。 14 | 以下は、URLを指定して接続を確立する中で証明書の検証が行われます。 15 | 16 | ```java 17 | try { 18 | URL url = new URL("https://www.example.com"); 19 | HttpsURLConnection conn = (HttpsURLConnection)url.openConnection(); 20 | conn.connect(); 21 | : 22 | } catch (...) { 23 | : 24 | } 25 | ``` 26 | 27 | デバッグでのみ使用したい接続先を指定したい場合は、Android 7.0(API 24)以降で利用可能なNetwork Security Configurationを使用してください。 28 | 詳しくは[「Network Security Configuration | Android Developers」][2]および[「Androidアプリのセキュア設計・セキュアコーディングガイド」][3]を参照してください。 29 | 30 | HTTPSで接続するアプリをデバッグする場合には、マニフェストに記載した設定ファイルにdebug-overridesタグを使用して、デバッグビルドでのみ使用するCAを指定することが出来ます。 31 | 32 | ``` 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | ``` 43 | 44 | 注意: デバッグビルドにするためにマニフェストにdebuggable属性を記述しないでください。詳しくは[HardcodedDebugMode](HardcodedDebugMode.md)の項を参照してください。 45 | 46 | ## 不適切な例 47 | 48 | javax.net.ssl.X509TrustManagerインタフェースを実装するクラスでは、本来checkServerTrustedメソッドおよびcheckClientTrustedメソッドで証明書の検証をします。 49 | しかし、デバッグなどのために証明書を検証しない実装にすると、中間者攻撃[^1]を受けるリスクになります。 50 | 51 | ```java 52 | X509TrustManager trustManager = new X509TrustManager() { 53 | : 54 | @Override 55 | public void checkServerTrusted(X509Certificate[] chain, String authType) 56 | throws CertificateException { 57 | // 何もしない -> どんな証明書でも受け付ける 58 | } 59 | 60 | @Override 61 | public void checkClientTrusted(X509Certificate[] chain, String authType) 62 | throws CertificateException { 63 | // 何もしない -> どんな証明書でも受け付ける 64 | } 65 | : 66 | }; 67 | 68 | SSLContext context = SSLContext.getInstance("TLS"); 69 | context.init( 70 | null, 71 | new TrustManager[] { trustManager }, 72 | new SecureRandom() 73 | ); 74 | 75 | HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory()); 76 | HttpsURLConnection conn = (HttpsURLConnection)new URL(url).openConnection(proxy); 77 | conn.connect(); 78 | ``` 79 | 80 | Lintは、checkServerTrusted()、checkClientTrusted()に有効なコードが存在しないことを検知すると、それぞれ次のような警告メッセージを出力します。 81 | 82 | - Lint出力(Warning) 83 | "'checkServerTrusted' is empty, which could cause insecure network traffic due to trusting arbitrary TLS/SSL certificates presented by peers" 84 | "'checkClientTrusted' is empty, which could cause insecure network traffic due to trusting arbitrary TLS/SSL certificates presented by peers" 85 | 86 | このチェックは簡易的なもののため、証明書検証の正当性は判断できません。例えば、ログ出力の一行だとしても「有効なコードは存在する」ということでメッセージは出力されなくなります。 87 | 独自TrustManagerを実装する場合は、証明書検証を適切に行えているかを慎重に確認する必要があります。 88 | 89 | ## 外部リンク 90 | 91 | - [X509TrustManager | Android Developers][1] 92 | - [Network Security Configuration | Android Developers][2] 93 | - [Android アプリのセキュア設計・セキュアコーディングガイド 5.4.2.4. 独自の TrustManager を作らない(必須)][3] 94 | - [プレス発表 【注意喚起】HTTPSで通信するAndroidアプリの開発者はSSLサーバー証明書の検証処理の実装を][4] 95 | 96 | 97 | [1]: https://developer.android.com/reference/javax/net/ssl/X509TrustManager.html 98 | [2]: https://developer.android.com/training/articles/security-config.html 99 | [3]: http://www.jssec.org/dl/android_securecoding/5_how_to_use_security_functions.html#%E7%8B%AC%E8%87%AA%E3%81%AEtrustmanager%E3%82%92%E4%BD%9C%E3%82%89%E3%81%AA%E3%81%84-%EF%BC%88%E5%BF%85%E9%A0%88%EF%BC%89 100 | [4]: https://www.ipa.go.jp/about/press/20140919_1.html 101 | 102 | [^1]: dummy "中間者攻撃:通信している2人のユーザーの間に第三者が介在し、送信者と受信者の両方になりすまして、ユーザーが気付かないうちに通信を盗聴したり、制御したりすること" 103 | -------------------------------------------------------------------------------- /UnprotectedSMSBroadcastReceiver.md: -------------------------------------------------------------------------------- 1 | # Unprotected SMS BroadcastReceiver(UnprotectedSMSBroadcastReceiver) 2 | 3 | ## 警告されている問題点 4 | 5 | BroadcastReceiverの保護が不十分なため、意図しないSMS Broadcast[^注釈1]を受信し、フィッシングサイトへの誘導や重要情報の漏洩のリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - Broadcastの送信元にBROADCAST\_SMSパーミッションが付与されていることを確認する 10 | 11 | note: Android 6.0(API 23)以上の端末では、第三者アプリがSMS Broadcast[^注釈1]を送信できないため、minSdkVersionが23以上の場合は、[Unsafe Protected BroadcastReceiver][UnsafeProtectedBroadcastReceiver]の項の受信Intentの安全性を確認する対策でも問題が発生しなくなります。 12 | 13 | ## 対策の具体的例 14 | 15 | Signatureパーミッション[^注釈2]であるandroid.permission.BROADCAST\_SMSをBroadcastReceiverに指定することで、第三者アプリが送信したIntentを受信しないようにできます。 16 | 17 | (静的BroadcastReceiverの例) 18 | 19 | ``` 20 | 23 | 24 | 25 | 26 | 27 | ``` 28 | 29 | (動的BroadcastReceiverの例) 30 | 31 | ```java 32 | public class MainActivity extends AppCompatActivity { 33 | private BroadcastReceiver mReceiver = new BroadcastReceiver() { 34 | @Override 35 | public void onCreate(Context context, Intent intent) { 36 | ... 37 | } 38 | }; 39 | 40 | @Override 41 | public void onResume() { 42 | super.onResume(); 43 |     // IntentFilterでSMS受信を設定し、パーミッションを指定する 44 | registerReceiver(mReceiver, 45 | new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION), 46 | Manifest.permission.BROADCAST_SMS, 47 | new Handler(getMainLooper())); 48 | } 49 | 50 | @Override 51 | public void onPause() { 52 | super.onPause(); 53 | unregisterReceiver(mReceiver); 54 | } 55 | } 56 | ``` 57 | 58 | ## 不適切な例 59 | 60 | 第三者アプリが送信するSMS Broadcastを無条件に受信し処理してしまうと、攻撃者が細工した​データが含まれている可能性があり危険です。 61 | 62 | (静的BroadcastReceiverの例) 63 | 64 | ``` 65 | 66 | 68 | 69 | 70 | 71 | 72 | ``` 73 | 74 | (動的BroadcastReceiverの例) 75 | 76 | ```java 77 | @Override 78 | protected void onResume() { 79 | super.onResume(); 80 | // IntentFilterのみ設定し、パーミッションを指定していない 81 | registerReceiver(mReceiverNoPermission, 82 | new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION)); 83 | } 84 | ``` 85 | 86 | Lintは、前者の静的ReceiverのようにSMS Broadcast[^注釈1]を受信する設定とし、かつ、BROADCAST\_SMS パーミッションの指定がないことを検知すると、次のようなメッセージを出力します。 87 | 88 | - Lint出力(Warning) 89 | "BroadcastReceivers that declare an intent-filter for SMS_DELIVER or SMS_RECEIVED must ensure that the caller has the BROADCAST_SMS permission, otherwise it is possible for malicious actors to spoof intents." 90 | 91 | Lintは、後者の動的Receiverの例を検知できません。 92 | 93 | ## 外部リンク 94 | 95 | - [BroadcastReceiver | Android Developers][1] 96 | 97 | [1]: https://developer.android.com/reference/android/content/BroadcastReceiver.html 98 | 99 | [UnsafeProtectedBroadcastReceiver]: UnsafeProtectedBroadcastReceiver.md 100 | 101 | 102 | [^注釈1]: javascript:void(0); "SMS Broadcast:SMS_DELIVERまたはSMS_RECEIVEをActionに持つBroadcast Intentのこと。" 103 | [^注釈2]: javascript:void(0); "Signatureパーミッション:同じ証明書で署名されているアプリにのみ利用を許可するパーミッションのこと。" 104 | 105 | -------------------------------------------------------------------------------- /UnsafeDynamicallyLoadedCode.md: -------------------------------------------------------------------------------- 1 | # load used to dynamically load code (UnsafeDynamicallyLoadedCode) 2 | 3 | ## 警告されている問題点 4 | 5 | 安全ではないライブラリ[^注釈1]を使用する可能性があるため、アプリの情報・機能が不正に利用されるリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | 以下のすべての対策を実施してください。 10 | 11 | - アプリが持つ共有ライブラリはアプリのライブラリディレクトリに配置する 12 | - 共有ライブラリのロード元は標準のライブラリディレクトリに限定する 13 | 14 | ## 対策の具体例 15 | 16 | ### 共有ライブラリをアプリ標準のライブラリディレクトリに配置する 17 | 18 | アプリ(APK)が保持する共有ライブラリ(.so)を使用する場合は、アプリのライブラリディレクトリ(lib)以外に配置することは避けてください。 19 | 詳細は[「Native code outside library directory」][3]を参照してください。 20 | 21 | ### 共有ライブラリのロード元を標準のライブラリディレクトリに限定する 22 | 23 | ライブラリのロードには、Runtime.loadLibrary()もしくはSystem.loadLibrary()を使用することで、ロード元をアプリのlibディレクトリを含む標準のライブラリディレクトリ(/system/lib、/vendor/libなど)に限定することができます。 24 | これらのディレクトリは、systemあるいはroot権限が設定されており、一般アプリはファイルの読み込みのみが許可されています。そのため攻撃者による改竄のリスクが低く抑えられます。 25 | 26 | 以下はloadLibrary()の使用例です。 27 | 28 | ```java 29 | public class MainActivity extends AppCompatActivity { 30 | static { 31 | // ライブラリディレクトリのlibhello.soを読み込み 32 | System.loadLibrary("hello"); 33 | } 34 | 35 | // 読み込むライブラリにあるメソッドを定義 36 | public native String sampleMethod(); 37 | 38 | @Override 39 | protected void onCreate(Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | setContentView(R.layout.activity_main); 42 | 43 | //ライブラリのメソッド呼び出し 44 | Log.i("", sampleMethod()); 45 | } 46 | } 47 | ``` 48 | 49 | ## 不適切な例 50 | 51 | Runtime.load()もしくはSystem.load()は任意のパスのライブラリをロードすることができますが、第三者アプリによる書き換えのリスクが高くなります。 52 | 53 | ```java 54 | public class MainActivity extends Activity { 55 | private class Loader { 56 | public void load() { 57 | try { 58 | // アプリ内データ領域からロード 59 | String mydir = getFilesDir().getPath(); 60 | Runtime.getRuntime().load(mydir + "/libhello1.so"); 61 | 62 | // アプリ固有外部ストレージからロード 63 | String myexdir = getExternalFilesDir(null).getPath(); 64 | System.load(myexdir + "libhello2.so"); 65 | } catch (SecurityException ignore) { 66 | ... 67 | } catch (UnsatisfiedLinkError ignore) { 68 | ... 69 | } catch (NullPointerException ignore) { 70 | ... 71 | } 72 | } 73 | } 74 | 75 | @Override 76 | protected void onCreate(Bundle savedInstanceState) { 77 | super.onCreate(savedInstanceState); 78 | setContentView(R.layout.activity_main); 79 | Loader ld = new Loader(); 80 | ld.load(); 81 | } 82 | } 83 | ``` 84 | 85 | Lintは、load()の使用を検知すると、次のようなメッセージを出力します。 86 | 87 | - Lint出力(Warning) 88 | "Dynamically loading code using \`load\` is risky, please use \`loadLibrary\` instead when possible." 89 | 90 | ## 外部リンク 91 | 92 | - [Runtime | Android Developers][1] 93 | - [System | Android Develpers][2] 94 | 95 | 96 | [1]:https://developer.android.com/reference/java/lang/Runtime.html 97 | [2]:https://developer.android.com/reference/java/lang/System.html 98 | [3]:UnsafeNativeCodeLocation.md 99 | 100 | 101 | [^注釈1]: javascript:void(0); "ライブラリ:C/C++言語で記述されたネイティブコードをビルドした実行形式のバイナリファイル(標準的なファイルの拡張子は“.so”)" 102 | -------------------------------------------------------------------------------- /UnsafeNativeCodeLocation.md: -------------------------------------------------------------------------------- 1 | # Native code outside library directory (UnsafeNativeCodeLocation) 2 | 3 | ## 警告されている問題点 4 | 5 | 共有ライブラリ[^注釈1]をアプリのライブラリディレクトリ以外に配置しているため、ファイルが書き換えられ、アプリの情報・機能が不正に利用されるリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - 動的にロードされる共有ライブラリをアプリのライブラリディレクトリに配置する 10 | 11 | ## 対策の具体例 12 | 13 | 共有ライブラリ(.so)をインストール時にアプリのライブラリディレクトリ(/data/data/<package>/lib)に正しく展開するには、アプリケーションパッケージ(APK)を適切に構成します。 14 | ライブラリディレクトリはアプリ自身も書込不可となっているので、第三者アプリによる改竄などのリスクが抑えられます。 15 | 16 | Android Studioを利用する場合の手順については[「プロジェクトへの C/C++ コードの追加」][2]を参照してください。 17 | 18 | [Native Development Kit(NDK)][1]やそのほかの開発プラットフォームの場合もそれぞれ対応する利用ガイドなどを参照してください。 19 | 20 | ## 不適切な例 21 | 22 | 共有ライブラリをlib以外のassetsやresディレクトリに格納、もしくはソース中にバイナリイメージを埋め込むことができます。 23 | このような共有ライブラリを使用するには、**自前で**APKファイルから.soファイルを取り出して、端末に配置する必要があります。 24 | このとき、ファイルの配置やアクセス権限の設定を誤ると第三者アプリから読み書き可能になり、悪意のあるコードの埋め込みおよび実行のリスクとなります。 25 | 26 | Lintは、resあるいはassetsディレクトリの下に共有ライブラリが配置されていることを検知すると、そのファイルの拡張子に応じて次のようなメッセージを出力します。 27 | 28 | - Lint出力 29 | <ファイルの拡張子が“.so”のとき > 30 | “Shared libraries should not be placed in the res or assets directories. Please use the features of your development environment to place shared libraries in the lib directory of the compiled APK.” 31 | 32 | <ファイルの拡張子が“.so”以外のとき> 33 | “Embedding non-shared library native executables into applications should be avoided when possible, as there is an increased risk that the executables could be tampered with after installation. Instead, native code should be placed in a shared library, and the features of the development environment should be used to place the shared library in the lib directory of the compiled APK.” 34 | 35 | Lintは、ソースコードに埋め込まれたライブラリのバイナリイメージを検知することはできません。 36 | 37 | ## 外部リンク 38 | 39 | - [NDK のガイド][1] 40 | - [プロジェクトへの C / C++ コードの追加 | Android Studio][2] 41 | 42 | 43 | [1]:https://developer.android.com/ndk/guides/index.html 44 | [2]:https://developer.android.com/studio/projects/add-native-code.html 45 | 46 | 47 | [^注釈1]: javascript:void(0); "共有ライブラリ:C/C++言語で記述されたネイティブコードをビルドした実行形式のバイナリファイル(標準的なファイルの拡張子は“.so”) " 48 | 49 | -------------------------------------------------------------------------------- /UnsafeProtectedBroadcastReceiver.md: -------------------------------------------------------------------------------- 1 | # Unsafe Protected BroadcastReceiver(UnsafeProtectedBroadcastReceiver) 2 | 3 | ## 警告されている問題点 4 | 5 | 受信したIntentの安全性を確認していないため、意図しない処理の実行や重要情報漏洩のリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - 受信Intentの安全性を確認する 10 | 11 | ## 対策の具体例 12 | 13 | 公開BroadcastReceiverは、悪意のある偽装Intentを受け取る可能性があります。 14 | 非公開BroadcastReceiverであっても、同一アプリ内で他のアプリから受け取った情報を転送することがあるため、受信したIntentの安全性を確認してください。 15 | BroadcastReceiverの公開非公開に拘らず、受信したIntentのAction文字列を最低限確認し、データの安全性も十分に確認してください。 16 | 17 | ``` 18 | 21 | 22 | 23 | 24 | 25 | ``` 26 | 27 | ```java 28 | public class BatteryLowReceiver extends BroadcastReceiver { 29 | private static final String MY_BROADCAST_PUBLIC = 30 | "com.example.broadcast.MY_BROADCAST_PUBLIC"; 31 | 32 | @Override 33 | public void onReceive(Context context, Intent intent) { 34 | // 受信したIntentのAction文字列が期待したものであることを確認する 35 | if (!MY_BROADCAST_PUBLIC.equals(intent.getAction())) return; 36 | 37 | Bundle extras = intent.getExtras(); 38 | //データの安全性も確認する 39 | ... 40 | } 41 | } 42 | ``` 43 | 44 | 注意: アプリがAndroid 8.0を対象にしている場合は、暗黙的Broadcastを受信する静的Receiverを登録できないため、動的Receiverを使用する必要があります。ただし、静的Receiver登録が可能な[例外][broadcast_exception]があります。 45 | 46 | 非公開BroadcastReceiverに対しては、intent-filterにシステムだけが送信するBroadcast[^注釈1]のみ設定するようにしてください。 47 | 同一アプリ内に指定のIntentを投げたつもりでも、他アプリの公開Receiverが受け取る可能性があるからです。 48 | 49 | ``` 50 | 53 | 54 | 55 | 56 | 57 | 58 | ``` 59 | 60 | ## 不適切な例 61 | 62 | 受け取ったIntentには攻撃者が細工した​データが含まれている可能性があるため、Intentの安全性を確認せずに使用することにはリスクがあります。 63 | 64 | (動的BroadcastReceiverの例) 65 | 66 | ```java 67 | public class MainActivity extends AppCompatActivity { 68 | private BroadcastReceiver mReceiver = new BroadcastReceiver() { 69 | @Override 70 | public void onReceive(Context context, Intent intent) { 71 | //Action文字列もデータも確認なし 72 | ... 73 | } 74 | }; 75 | 76 | @Override 77 | protected void onResume() { 78 | super.onResume(); 79 | registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_BATTERY_LOW)); 80 | } 81 | 82 | @Override 83 | protected void onPause() { 84 | super.onPause(); 85 | unregisterReceiver(mReceiver); 86 | } 87 | } 88 | ``` 89 | 90 | (静的BroadcastReceiverの例) 91 | 92 | ``` 93 | 94 | 95 | 96 | 97 | 98 | ``` 99 | 100 | ```java 101 | public class BatteryLowReceiver extends BroadcastReceiver { 102 | @Override 103 | public void onReceive(Context context, Intent intent) { 104 | //Action文字列の確認なし 105 | ... 106 | 107 | Bundle extras = intent.getExtras(); 108 | ... 109 | } 110 | } 111 | ``` 112 | 113 | Lintは、後者の静的Receiverのように<intent-filter>でシステム送信のBroadcastを受信する設定とし、かつ、受信したIntentのAction文字列の未確認を検知すると、次のようなメッセージを出力します。 114 | 115 | - Lint出力(Warning) 116 | "This broadcast receiver declares an intent-filter for a protected broadcast action string, which can only be sent by the system, not third-party applications. However, the receiver's onReceive method does not appear to call getAction to ensure that the received Intent's action string matches the expected value, potentially making it possible for another actor to send a spoofed intent with no action string or a different action string and cause undesired behavior." 117 | 118 | ## 外部リンク 119 | 120 | - [Androidアプリのセキュア設計・セキュアコーディングガイド 4.2 Broadcast を受信する・送信する][1] 121 | - [Android 8.0での暗黙的Broadcastの動作変更][2] 122 | - [暗黙的なブロードキャストの例外(Implicit Broadcast Exceptions)][broadcast_exception] 123 | 124 | [1]: http://www.jssec.org/dl/android_securecoding/4_using_technology_in_a_safe_way.html#broadcast%E3%82%92%E5%8F%97%E4%BF%A1%E3%81%99%E3%82%8B%E3%83%BB%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B 125 | [2]: https://developer.android.com/about/versions/oreo/android-8.0-changes.html 126 | [broadcast_exception]: https://developer.android.com/guide/components/broadcast-exceptions.html 127 | 128 | 129 | [^注釈1]: javascript:void(0); "システムだけが送信するBroadcast:Androidシステムが送信するBroadcast。BATTERY_LOW、BOOT_COMPLETED、SCREEN_ON等が該当する。" 130 | 131 | -------------------------------------------------------------------------------- /UseCheckPermission.md: -------------------------------------------------------------------------------- 1 | # Using the result of check permission calls (UseCheckPermission) 2 | 3 | ## 警告されている問題点 4 | 5 | 呼び出し元へのパーミッション付与を「実質的に」確認していないため、重要情報の漏洩等が発生するリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - コンポーネントの機能及び情報へのアクセスを許可する際は、呼び出し元のパーミッションを確認する 10 | 11 | ## 対策の具体例 12 | 13 | パーミッションを確認するメソッドには挙動の異なる2種類があります。実装のスタイルに合わせて使い分けてください。 14 | 15 | ### パーミッションが付与されていないと例外が発生する 16 | 17 | enforcePermission系のメソッドは、指定するパーミッションが付与されていない場合に例外を発生させます。 18 | 以下の例では、パーミッションが付与されていない呼び出し元に例外が返ります。 19 | 20 | ```java 21 | public void onCreate(Bundle savedInstanceState) { 22 | ... 23 | // 呼び出し元に位置情報パーミッションが付与されていなければ例外が発生します 24 | enforceCallingPermission(Manifest.permission.READ_CONTACTS, 25 | "Requires permission " + Manifest.permission.READ_CONTACTS); 26 | 27 | // パーミッションが付与されていた場合の処理 28 | ... 29 | } 30 | ``` 31 | 32 | ### パーミッションの付与の状態を返却する 33 | 34 | checkPermission系のメソッドは、指定するパーミッションの検査結果を値で返しますので、戻り値を確認して処理を適切に行ってください。 35 | 以下の例では、パーミッションが適切に付与されている場合に位置情報が返ります。 36 | 37 | ```java 38 | Intent userData = new Intent(); 39 | userData.putExtra(...); 40 | ... 41 | 42 | if (checkCallingPermission(Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) { 43 | // 呼び出し元に位置情報のパーミッションが付与されている場合にのみ位置情報を付加する 44 | userData.putExtra("location", locationData); 45 | } 46 | 47 | setIntent(userData); 48 | setResult(RESULT_OK); 49 | ``` 50 | 51 | ## 不適切な例 52 | 53 | 次の例では、checkCallingPermissionの戻り値に応じた処理をしていないため、呼び出し元のパーミッション付与の状態にかかわらず、常に位置情報を返してしまいます。 54 | 55 | ```java 56 | Intent userData = new Intent(); 57 | userData.putExtra(...); 58 | ... 59 | // メソッドの結果を判定していない 60 | checkCallingPermission(Manifest.permission.ACCESS_COARSE_LOCATION); 61 | // 位置情報のパーミッションを付与されていないアプリにも位置情報を渡してしまう 62 | userData.putExtra("location", locationData); 63 | 64 | setIntent(userData); 65 | setResult(RESULT_OK); 66 | ``` 67 | 68 | 例外を投げる__enforce__CallingPermissionメソッドと誤って付与状態を返す__check__CallingPermissionメソッドを使用すると、このようなことになります。 69 | 70 | Lintは、checkCallingPermissionメソッドなどの戻り値が使用されていないことを検知すると、次のようなメッセージを出力します。 71 | 72 | - Lint出力(Warning) 73 | "The result of checkCallingPermission is not used; did you mean to call enforceCallingPermission." 74 | 75 | ## 外部リンク 76 | 77 | - [Context | Android Developers][1] 78 | - [Androidアプリのセキュア設計・セキュアコーディングガイド 5.2.3.4. Permission の再委譲問題][2] 79 | - [Felt, Adrienne Porter, et al. “Permission Re-Delegation: Attacks and Defenses.” USENIX Security Symposium. Vol. 30. 2011.][3] 80 | 81 | [1]: https://developer.android.com/reference/android/content/Context.html 82 | [2]: http://www.jssec.org/dl/android_securecoding/5_how_to_use_security_functions.html#permission%E3%81%AE%E5%86%8D%E5%A7%94%E8%AD%B2%E5%95%8F%E9%A1%8C 83 | [3]: https://www.usenix.org/event/sec11/tech/full_papers/Felt.pdf 84 | 85 | -------------------------------------------------------------------------------- /UsingHttp.md: -------------------------------------------------------------------------------- 1 | # Using HTTP instead of HTTPS (UsingHttp) 2 | 3 | ## 警告されている問題点 4 | 5 | Gradleの配布元URLにhttpを使用しているため、中間者攻撃[^1]によりアプリを制御されてしまうリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - Gradleラッパーの設定ファイルgradle-wrapper.propertiesのdistributionUrlはhttpsから始まるURLを指定する 10 | 11 | ## 対策の具体例 12 | 13 | プロジェクトのビルドに使用するGradleのバイナリを指定する場合、中間者攻撃[^1]を受けないようにするためgradle/wrapper/gradle-wrapper.propertiesのdistributionUrlはhttpsプロトコルで指定してください。 14 | 15 | distributionUrl = https\://services.gradle.org/distributions/gradle-3.3-all.zip 16 | 17 | 過去のAndroid Studioではhttpを使用していましたが、現在はhttpsがデフォルトになっています。http設定の既存のプロジェクトはhttps設定に修正してください。 18 | 19 | ## 不適切な例 20 | 21 | 以下は、gradleのURLをhttpで指定しているため、中間者攻撃[^1]を受けるリスクがあります。 22 | 23 | distributionUrl = http\://services.gradle.org/distributions/gradle-3.3-all.zip 24 | 25 | Lintは、gradle/wrapper/gradle-wrapper.propertiesのdistributionUrlにhttpのURL指定を検出すると、次のようなメッセージを出力をします。 26 | 27 | - Lint出力(Warning) 28 | "Replace HTTP with HTTPS for better security; use https\\://services.gradle.org/distributions/gradle-3.3-all.zip" 29 | 30 | ## 外部リンク 31 | 32 | - [Android Plugin for Gradle Release Notes][1] 33 | - [Gradle Docs 4.3.1 「Chapter 6. The Gradle Wrapper」][2] 34 | 35 | 36 | [1]: https://developer.android.com/studio/releases/gradle-plugin.html?hl=ja\#updating-gradle 37 | [2]: https://docs.gradle.org/4.3.1/userguide/gradle_wrapper.html 38 | 39 | [^1]: dummy "中間者攻撃:通信している2人のユーザーの間に第三者が介在し、送信者と受信者の両方になりすまして、ユーザーが気付かないうちに通信を盗聴したり、制御したりすること" 40 | -------------------------------------------------------------------------------- /VulnerableColdovaVersion.md: -------------------------------------------------------------------------------- 1 | # Vulnerable Cordova Version(VulnerableCordovaVersion) 2 | 3 | ## 警告されている問題点 4 | 5 | 問題のあるバージョンのCordovaが利用されているため、アプリを改変される可能性があります。 6 | 7 | ## 対策のポイント 8 | 9 | - 問題が修正されたバージョン(4.1.1以上)のCordovaを利用する 10 | 11 | ## 対策の具体例 12 | 13 | 2016年7月11日以降、Google Playではバージョン4.1.1より前のApache Cordovaを使用するすべての新規アプリおよびアップデートの公開が禁止されています。 14 | 速やかにApache Cordova v.4.1.1 以降にアップグレードし、Cordova CLIでプラットフォーム追加の際は4.1.1以降を指定してください。 15 | アップグレードの詳細は[Apache Cordova のウェブサイト][4]を参照してください。 16 | 17 | ``` 18 | # cd 19 | # cordova platform add android@latest 20 | ``` 21 | 22 | latestは最新バージョンが適用されます。 23 | 24 | ## 不適切な例 25 | 26 | Cordova CLIでプラットフォームを追加する際に4.1.1より前のバージョンを指定しないでください。 27 | 28 | ``` 29 | # cd 30 | # cordova platform add android@3.6.4 31 | ``` 32 | 33 | Lintは使用しているCordovaのバージョンが4.1.1より前であることを検出すると、次のようなメッセージを出力をします。 34 | 35 | - Lint結果 36 | "You are using a vulnerable version of Cordova: 3.6.4" 37 | 38 | ## 外部リンク 39 | 40 | - [CVE-2015-5256][1] 41 | URLホワイトリストの回避による不正なコンテンツの読み込みが可能になっていたという脆弱性 42 | - [CVE-2015-8320][2] 43 | Java機能呼び出しに必要な擬似乱数が予測可能になっていたという脆弱性 44 | - [「Apache Cordova」を使ったハイブリッドアプリケーションの脆弱性に関する調査報告書][3] 45 | CVE-2015-5256の詳細な解説 46 | 47 | [1]: http://jvndb.jvn.jp/ja/contents/2015/JVNDB-2015-000187.html 48 | [2]: http://jvndb.jvn.jp/ja/contents/2015/JVNDB-2015-006002.html 49 | [3]: https://github.com/JPCERTCC/cordova 50 | [4]: https://cordova.apache.org/docs/en/7.x/guide/platforms/android/upgrade.html 51 | 52 | -------------------------------------------------------------------------------- /VulnerableCordovaVersion.md: -------------------------------------------------------------------------------- 1 | # Vulnerable Cordova Version(VulnerableCordovaVersion) 2 | 3 | ## 警告されている問題点 4 | 5 | 問題のあるバージョンのCordovaを利用しているため、アプリを改変される可能性があります。 6 | 7 | ## 対策のポイント 8 | 9 | - 問題が修正されたバージョン(4.1.1以上)のCordovaを利用する 10 | 11 | ## 対策の具体例 12 | 13 | 2016年7月11日以降、Google Playではバージョン4.1.1より前のApache Cordovaを使用するすべての新規アプリおよびアップデートの公開が禁止されています。 14 | 速やかにApache Cordova v.4.1.1 以降にアップグレードし、Cordova CLIでプラットフォーム追加の際は4.1.1以降を指定してください。 15 | アップグレードの詳細は[Apache Cordova のウェブサイト][4]を参照してください。 16 | 17 | ``` 18 | # cd 19 | # cordova platform add android@latest 20 | ``` 21 | 22 | latestは最新バージョンが適用されます。 23 | 24 | ## 不適切な例 25 | 26 | Cordova CLIでプラットフォームを追加する際に4.1.1より前のバージョンを指定しないでください。 27 | 28 | ``` 29 | # cd 30 | # cordova platform add android@3.6.4 31 | ``` 32 | 33 | Lintは、使用しているCordovaのバージョンが4.1.1より前であることを検出すると、次のようなメッセージを出力をします。 34 | 35 | - Lint結果 36 | "You are using a vulnerable version of Cordova: 3.6.4" 37 | 38 | ## 外部リンク 39 | 40 | - [CVE-2015-5256][1] 41 | - [CVE-2015-8320][2] 42 | - [「Apache Cordova」を使ったハイブリッドアプリケーションの脆弱性に関する調査報告書][3] 43 | 44 | [1]: http://jvndb.jvn.jp/ja/contents/2015/JVNDB-2015-000187.html 45 | [2]: http://jvndb.jvn.jp/ja/contents/2015/JVNDB-2015-006002.html 46 | [3]: https://github.com/JPCERTCC/cordova 47 | [4]: https://cordova.apache.org/docs/en/7.x/guide/platforms/android/upgrade.html 48 | -------------------------------------------------------------------------------- /WorldReadableFiles.md: -------------------------------------------------------------------------------- 1 | # openFileOutput() or similar call passing MODE\_WORLD\_READABLE (WorldReadableFiles) 2 | 3 | ## 警告されている問題点 4 | 5 | ファイルを任意のアプリから読める設定にしているため、重要な情報が漏洩するリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - アプリ利用のファイルはアプリディレクトリ[^注釈1]内に非公開で作成する 10 | 11 | ## 対策の具体例 12 | 13 | 非公開でファイルを作成する方法は[File.setReadable() used to make file world-readable][4]に同じなのでそちらを参照してください。 14 | 15 | ## 不適切な例 16 | 17 | 以下の例では他のアプリから読み込み可能なモードでファイルを作成/オープンしているため、情報の流出を防ぐことができません。 18 | 19 | ```java 20 | try { 21 | // ローカルファイルを他のアプリから読み込み可能モードで作成/オープン 22 | FileOutputStream myfile = openFileOutput(FILE_NAME, MODE_WORLD_READABLE); 23 | 24 | // ローカル設定ファイルを他のアプリから読み込み可能モードで作成/オープン 25 | SharedPreferences mypref = getSharedPreferences(PREFS_NAME, MODE_WORLD_READABLE); 26 | 27 | // ローカルディレクトリを他のアプリから読み込み可能モードで作成/オープン 28 | File mydir = getDir(DIR_NAME, MODE_WORLD_READABLE); 29 | 30 | // 同様のメソッドは他にopenOrCreateDatabaseがあります 31 | } catch (IOException e) { 32 | (省略) 33 | } 34 | ``` 35 | 36 | Lintは、上の例のようにopenFileOutput()、getSharedPreferences()およびgetDir()がWORLD_READABLEを第2引数として呼び出されていることを検知すると、次のようなメッセージを出力します 37 | 38 | - Lint 出力 (警告) 39 | "Using 'MODE_WORLD_READABLE' when creating files can be risky, review carefully." 40 | 41 | 注意: 以前はMODE_WORLD_READABLE / MODE_WORLD_WRITEABLEが使用できましたが、Android 4.2(API 17)で非推奨となり、Android 7.0(API 24)以降の端末では、これらのモード指定では機能しなくなりました。 42 | 43 | ## 外部リンク 44 | 45 | - [Context | Android Developers][1] 46 | - [Androidアプリのセキュア設計・セキュアコーディングガイド 4.6.ファイルを扱う][2] 47 | - [Sharing Files | Android Developers][3] 48 | 49 | [1]:https://developer.android.com/reference/android/content/Context.html 50 | [2]:http://www.jssec.org/dl/android_securecoding/4_using_technology_in_a_safe_way.html#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E6%89%B1%E3%81%86 51 | [3]:https://developer.android.com/training/secure-file-sharing/index.html 52 | [4]:SetWorldReadable.md 53 | 54 | 55 | [^注釈1]: javascript:void(0); "アプリディレクトリ:アプリがインストールされた端末内のストレージ。通常、/data/data/<package-name>を指す。" 56 | -------------------------------------------------------------------------------- /WorldWritableFiles.md: -------------------------------------------------------------------------------- 1 | # openFileOutput() or similar call passing MODE\_WORLD\_WRITEABLE (WorldWritableFiles) 2 | 3 | ## 警告されている問題点 4 | 5 | ファイルを任意のアプリから書き込める設定にしているため、重要な情報が改竄されたり、破壊されるリスクがあります。 6 | 7 | ## 対策のポイント 8 | 9 | - アプリ利用のファイルはアプリディレクトリ[^注釈1]内に非公開で作成する 10 | 11 | ## 対策の具体例 12 | 13 | 非公開でファイルを作成する方法は[File.setReadable() used to make file world-readable][4]に同じなのでそちらを参照してください。 14 | 15 | ## 不適切な例 16 | 17 | 以下の例では他のアプリから書き込み可能なモードでファイルを作成/オープンしているため、情報の確実性を保証することができません。 18 | 19 | ```java 20 | try { 21 | // ローカルファイルを他のアプリから書き込み可能モードで作成/オープン 22 | FileOutputStream myfile = openFileOutput(FILE_NAME, MODE_WORLD_WRITEABLE); 23 | 24 | // ローカル設定ファイルを他のアプリから書き込み可能モードで作成/オープン 25 | SharedPreferences mypref = getSharedPreferences(PREFS_NAME, MODE_WORLD_WRITEABLE); 26 | 27 | // ローカルディレクトリを他のアプリから書き込み可能モードで作成/オープン 28 | File mydir = getDir(DIR_NAME, MODE_WORLD_WRITEABLE); 29 | 30 | // 同様のメソッドは他にopenOrCreateDatabaseがあります 31 | } catch (IOException e) { 32 | (省略) 33 | } 34 | ``` 35 | 36 | 37 | Lintは、上の例のようにopenFileOutput()、getSharedPreferences()およびgetDir()がWORLD_WRITEABLEを第2引数として呼び出されていることを検知すると、次のようなメッセージを出力します。 38 | 39 | - Lint出力(Warning) 40 | "Using 'MODE_WORLD_WRITEABLE’ when creating files can be risky, review carefully." 41 | 42 | 注意: 以前はMODE_WORLD_READABLE / MODE_WORLD_WRITEABLEが使用できましたが、Android 4.2(API 17)で非推奨となり、Android 7.0(API 24)以降の端末では、これらのモード指定では機能しなくなりました。 43 | 44 | ## 外部リンク 45 | 46 | - [Context | Android Developers][1] 47 | - [Androidアプリのセキュア設計・セキュアコーディングガイド 4.6.ファイルを扱う][2] 48 | - [Sharing Files | Android Developers][3] 49 | 50 | [1]:https://developer.android.com/reference/android/content/Context.html 51 | [2]:http://www.jssec.org/dl/android_securecoding/4_using_technology_in_a_safe_way.html#%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E6%89%B1%E3%81%86 52 | [3]:https://developer.android.com/training/secure-file-sharing/index.html 53 | [4]:SetWorldReadable.md 54 | 55 | 56 | 57 | [^注釈1]: javascript:void(0); "アプリディレクトリ:アプリがインストールされた端末内のストレージ。通常、/data/data/<package-name>を指す。" 58 | -------------------------------------------------------------------------------- /WrongConstant.md: -------------------------------------------------------------------------------- 1 | # Incorrect constant (WrongConstant) 2 | 3 | ## 警告されている問題点 4 | 5 | メソッドの戻り値や、パラメータなどに想定外の値が入力され、アプリを正しく実行できない可能性があります。 6 | 7 | ## 対策のポイント 8 | 9 | - コードとアノテーションが不一致な問題に対処する 10 | 11 | ## 対策の具体例 12 | 13 | Support Annotationsライブラリを使用すると、見落とされやすいnullポインター例外やリソースタイプの不一致などの問題を検出できるようになります。利用方法などの詳細はAndroid Studioの[アノテーションによるコード検査の改善のページ][0]を参照してください。 14 | ここでは、Typedefアノテーションの用例を紹介します。Typedefアノテーションは、パラメータ、戻り値、フィールド参照が特定の定数セット、または範囲内の値をとるように宣言するための仕組みです。 15 | 16 | 次の例では、openFileメソッドの引数typeには、アノテーションで宣言した定数DOC_WORD, DOC_EXCEL, DOC_PDFのいずれか1つを要求します。 17 | 18 | ```java 19 | @Retention(RetentionPolicy.SOURCE) 20 | @IntDef({DOC_WORD, DOC_EXCEL, DOC_PDF}) 21 | public @interface DocType {} 22 | 23 | public static final int DOC_WORD = 0; 24 | public static final int DOC_EXCEL = 1; 25 | public static final int DOC_PDF = 2; 26 | 27 | public void openFile(String filename, @DocType int type) { ... } 28 | ``` 29 | 30 | flag属性を有効にして、使用できる定数をフラグ(|、&、^など)で統合することもできます。 31 | 32 | ```java 33 | @Retention(RetentionPolicy.SOURCE) 34 | @IntDef(flag=true, value={FONT_BOLD, FONT_ITALIC, FONT_UNDERLINE}) 35 | public @interface TextStyle {} 36 | 37 | public static final int FONT_BOLD = 0x01; 38 | public static final int FONT_ITALIC = 0x02; 39 | public static final int FONT_UNDERLINE = 0x04; 40 | 41 | public void setTextStyle(@TextStyle int style) { ... } 42 | 43 | setTextStyle(FONT_BOLD|FONT_ITALIC); 44 | ``` 45 | 46 | [@IntRange][2] と組み合わせて、整数が指定された定数セットまたは範囲内の値をとるようにすることもできます。 47 | 48 | ## 不適切な例 49 | 50 | 「対策の具体例」で示したopenFileメソッドのtype引数に、アノテーションで宣言していない定数を使用することはコードの信頼性を損ないます。 51 | アノテーションと一致しないので警告を発生しますが、この警告が出てもアプリのコンパイルは可能です。 52 | 53 | ```java 54 | openFile("sample.doc", 0); // 宣言した定数の「値」であっても不適切 55 | ``` 56 | 57 | Lintは、上のようにアノテーションで宣言した定数以外の使用を検知すると、次のようなメッセージを出力します。 58 | 59 | - Lint出力(Error) 60 | "Must be one of: (アノテーションで宣言した定数の列挙)" 61 | 62 | また、DocTypeの例はflag属性を使用したアノテーション定義ではないため、フラグ(|、&、^ など)で引数のパターンを指定することができません。 63 | 64 | ```java 65 | openFile("sample.doc", DOC_WORD | DOC_PDF); 66 | ``` 67 | 68 | Lintは、上のようにflag属性を使用していないアノテーションでのフラグ使用を検知すると、次のようなメッセージを出力します。 69 | 70 | - Lint出力(Error) 71 | "Flag not allowed here" 72 | 73 | ## 外部リンク 74 | 75 | - [Improve Code Inspection with Annotations | Android Studio #Typedef annotations][1] 76 | 77 | 78 | [0]: https://developer.android.com/studio/write/annotations.html 79 | [1]: https://developer.android.com/studio/write/annotations.html#enum-annotations 80 | [2]: https://developer.android.com/reference/android/support/annotation/IntRange.html -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "useSideMenu": true, 3 | "lineBreaks": "gfm", 4 | //"additionalFooterText": "© Recruit Co., Ltd., ", 5 | "title": "Android Lint 利用ガイドライン", 6 | "anchorCharacter": "¶" 7 | } -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | # Android Lint 利用ガイドライン 2 | 3 | ## Android Lintとは 4 | 5 | Android LintはAndroid Development Tools16から導入された、ソースチェックツールです。 6 | Androidアプリケーションのソースから潜在的なものも含めて問題を検出し、警告してくれます。 7 | このコンテンツでは、その中からセキュリティに分類されるものについて具体的な対策を示しながら解説をします。 8 | 9 | 本コンテンツは、主に2018年2月頃の情報に基づいて記載しております。 10 | それ以降に発表された情報については随時更新していく予定ですが、最新の情報は[Android Developers](https://developer.android.com/)などをご参照ください。 11 | 12 | ## Android Lint のセキュリティメッセージ 13 | 14 | ### A 15 | 16 | [addJavascriptInterface Called](AddJavascriptInterface.md) 17 | [AllowBackup/FullBackupContent Problems](AllowBackup.md) 18 | 19 | ### C 20 | 21 | [Call to SSLCertificateSocketFactory.getInsecure()](SSLCertificateSocketFactoryGetInsecure.md) 22 | [Cipher.getInstance with ECB](GetInstance.md) 23 | [Code contains easter egg](EasterEgg.md) 24 | [Code might contain an auth leak](AuthLeak.md) 25 | [Content provider does not require permission](ExportedContentProvider.md) 26 | [Content provider shares everything](GrantAllUris.md) 27 | 28 | ### E 29 | 30 | [Exported service does not require permission](ExportedService.md) 31 | 32 | ### F 33 | 34 | [File.setReadable() used to make file world-readable](SetWorldReadable.md) 35 | [File.setWritable() used to make file world-writable](SetWorldWritable.md) 36 | 37 | ### H 38 | 39 | [Hardcoded value of android:debuggable in the manifest](HardcodedDebugMode.md) 40 | [Hardware Id Usage](HardwareIds.md) 41 | 42 | ### I 43 | 44 | [Incorrect constant](WrongConstant.md) 45 | [Insecure call to SSLCertificateSocketFactory.createSocket()](SSLCertificateSocketFactoryCreateSocket.md) 46 | [Insecure HostnameVerifier #1](AllowAllHostnameVerifier.md) 47 | [Insecure HostnameVerifier #2](BadHostnameVerifier.md) 48 | [Insecure TLS/SSL trust manager](TrustAllX509TrustManager.md) 49 | [Invalid Permission Attribute](InvalidPermission.md) 50 | 51 | ### L 52 | 53 | [load used to dynamically load code](UnsafeDynamicallyLoadedCode.md) 54 | 55 | ### M 56 | 57 | [Missing @JavascriptInterface on methods](JavascriptInterface.md) 58 | 59 | ### N 60 | 61 | [Native code outside library directory](UnsafeNativeCodeLocation.md) 62 | 63 | ### O 64 | 65 | [openFileOutput() or similar call passing MODE_WORLD_READABLE](WorldReadableFiles.md) 66 | [openFileOutput() or similar call passing MODE_WORLD_WRITEABLE](WorldWritableFiles.md) 67 | 68 | ### P 69 | 70 | [Packaged private key](PackagedPrivateKey.md) 71 | [Potential Multiple Certificate Exploit](PackageManagerGetSignatures.md) 72 | [PreferenceActivity should not be exported](ExportedPreferenceActivity.md) 73 | 74 | ### R 75 | 76 | [Receiver does not require permission](ExportedReceiver.md) 77 | 78 | ### S 79 | 80 | [signatureOrSystem permissions declared](SignatureOrSystemPermissions.md) 81 | 82 | ### U 83 | 84 | [Unprotected SMS BroadcastReceiver](UnprotectedSMSBroadcastReceiver.md) 85 | [Unsafe Protected BroadcastReceiver](UnsafeProtectedBroadcastReceiver.md) 86 | [Using a fixed seed with SecureRandom](SecureRandom.md) 87 | [Using HTTP instead of HTTPS](UsingHttp.md) 88 | [Using setJavaScriptEnabled](SetJavascriptEnabled.md) 89 | [Using the result of check permission calls](UseCheckPermission.md) 90 | 91 | ### V 92 | 93 | [Vulnerable Cordova Version](VulnerableCordovaVersion.md) 94 | 95 | ### W 96 | 97 | [Weak RNG](TrulyRandom.md) 98 | -------------------------------------------------------------------------------- /myStyles.css: -------------------------------------------------------------------------------- 1 | h2.md-inpage-anchor { 2 | border-left: 8px solid; 3 | padding: 4px 10px 4px 15px; 4 | } -------------------------------------------------------------------------------- /navigation.md: -------------------------------------------------------------------------------- 1 | # Android Lint 利用ガイドライン 2 | 3 | [TOP](index.md) 4 | 5 | [INDEX \[A-H\]]() 6 | 7 | * # A 8 | 9 | * [addJavascriptInterface Called](AddJavascriptInterface.md) 10 | * [AllowBackup/FullBackupContent Problems](AllowBackup.md) 11 | 12 | * # C 13 | 14 | * [Call to SSLCertificateSocketFactory.getInsecure()](SSLCertificateSocketFactoryGetInsecure.md) 15 | * [Cipher.getInstance with ECB](GetInstance.md) 16 | * [Code contains easter egg](EasterEgg.md) 17 | * [Code might contain an auth leak](AuthLeak.md) 18 | * [Content provider does not require permission](ExportedContentProvider.md) 19 | * [Content provider shares everything](GrantAllUris.md) 20 | 21 | * # E 22 | 23 | * [Exported service does not require permission](ExportedService.md) 24 | 25 | * # F 26 | 27 | * [File.setReadable() used to make file world-readable](SetWorldReadable.md) 28 | * [File.setWritable() used to make file world-writable](SetWorldWritable.md) 29 | 30 | * # H 31 | 32 | * [Hardcoded value of android:debuggable in the manifest](HardcodedDebugMode.md) 33 | * [Hardware Id Usage](HardwareIds.md) 34 | 35 | [INDEX \[I-O\]]() 36 | 37 | * # I 38 | 39 | * [Incorrect constant](WrongConstant.md) 40 | * [Insecure call to SSLCertificateSocketFactory.createSocket()](SSLCertificateSocketFactoryCreateSocket.md) 41 | * [Insecure HostnameVerifier #1](AllowAllHostnameVerifier.md) 42 | * [Insecure HostnameVerifier #2](BadHostnameVerifier.md) 43 | * [Insecure TLS/SSL trust manager](TrustAllX509TrustManager.md) 44 | * [Invalid Permission Attribute](InvalidPermission.md) 45 | 46 | * # L 47 | 48 | * [load used to dynamically load code](UnsafeDynamicallyLoadedCode.md) 49 | 50 | * # M 51 | 52 | * [Missing @JavascriptInterface on methods](JavascriptInterface.md) 53 | 54 | * # N 55 | 56 | * [Native code outside library directory](UnsafeNativeCodeLocation.md) 57 | 58 | * # O 59 | 60 | * [openFileOutput() or similar call passing MODE_WORLD_READABLE](WorldReadableFiles.md) 61 | * [openFileOutput() or similar call passing MODE_WORLD_WRITEABLE](WorldWritableFiles.md) 62 | 63 | [INDEX \[P-W\]]() 64 | 65 | * # P 66 | 67 | * [Packaged private key](PackagedPrivateKey.md) 68 | * [Potential Multiple Certificate Exploit](PackageManagerGetSignatures.md) 69 | * [PreferenceActivity should not be exported](ExportedPreferenceActivity.md) 70 | 71 | * # R 72 | 73 | * [Receiver does not require permission](ExportedReceiver.md) 74 | 75 | * # S 76 | 77 | * [signatureOrSystem permissions declared](SignatureOrSystemPermissions.md) 78 | 79 | * # U 80 | 81 | * [Unprotected SMS BroadcastReceiver](UnprotectedSMSBroadcastReceiver.md) 82 | * [Unsafe Protected BroadcastReceiver](UnsafeProtectedBroadcastReceiver.md) 83 | * [Using a fixed seed with SecureRandom](SecureRandom.md) 84 | * [Using HTTP instead of HTTPS](UsingHttp.md) 85 | * [Using setJavaScriptEnabled](SetJavascriptEnabled.md) 86 | * [Using the result of check permission calls](UseCheckPermission.md) 87 | 88 | * # V 89 | 90 | * [Vulnerable Cordova Version](VulnerableCordovaVersion.md) 91 | 92 | * # W 93 | 94 | * [Weak RNG](TrulyRandom.md) 95 | 96 | [gimmick:theme](cerulean) 97 | 98 | [gimmick:themechooser](Choose theme) --------------------------------------------------------------------------------