LINE株式会社は、2023年10月1日にLINEヤフー株式会社になりました。LINEヤフー株式会社の新しいブログはこちらです。 LINEヤフー Tech Blog

Blog


Android脆弱性検査の自動化に向けたJandroid導入レポート

こんにちは。LINEでセキュリティを担当しているPark Sunjooです。
LINEのセキュリティチームでは、リリース予定のサービスやアプリケーションのセキュリティリスクを事前に発見することで、プロダクトの安全性向上に努めています。サービスやアプリケーションのセキュリティ検査を行う際、過去にセキュリティ問題を引き起こしたコードと類似したパターンを使用していたり、セキュリティリスクの高いコーディングパターンを再利用することによる脆弱性を発見することが度々あります。このように頻発するセキュリティ上の問題を迅速かつ容易に検出するために、一般的なソリューションを使用したり、独自のツールを開発したりしています。本記事では、Androidアプリで利用可能な自動脆弱性検査ツール「Jandroid」をLINEのAndroidアプリに取り入れ、セキュリティ上の問題を発見した事例を紹介します。

Jandroidとは?

Jandroidは、F-Secure Labsが開発した脆弱性検査ツールです。Androguardというオープンソースをベースにして開発されました。Androguardは、Androidの実行ファイルを解析する役割を担っています。大きく分けて以下のような機能があります。

  • APKファイル情報の抽出
  • クラスとメソッドリストの抽出
  • 相互参照(cross reference)の分析

これらの機能をベースにして、Jandroidは、Androidアプリ上の脆弱性を持つメソッドやコードを検出する脆弱性パターンマッチング機能や、コーディングパターンをテンプレート化する機能を備えています。

Jandroidは脆弱なコードをどのようにして検出するか

Jandroidは、脆弱なコーディングパターンの検出に静的解析を用います。静的解析は、コンパイルされたコードでプログラムの実行フローを解析する方法です。コードの構造に問題がある、あるいはセキュリティリスクのあるコードが使われているなど、アプリケーションに脆弱なコーディングパターンが使われていないか検査できます。Jandroidの仕組みをより詳しく理解するために、脆弱なコーディングパターンを検出する流れを見ていきましょう。

Jandroidは、危険度の高いメソッドから、Androidアプリ内のアクティビティクラス(Activity class) までのコードフローを解析し、実際にアクティビティから該当のメソッドを呼び出し可能か検査することで、脆弱性を検出します。アクティビティとは、Android上で動作するコンポーネントのことで、アプリケーションを動作させる基盤となるものです。アクティビティから危険度の高いメソッドを呼び出せるということは、ユーザー情報をそのメソッドに渡すことでユーザーになりすましたり、Androidアプリの外からアクティビティをトリガーにして該当のメソッドを呼び出せてしまうということを意味します。

例えば、アクティビティ実行によって、java.lang.ProcessBuilderのようなコマンド実行が可能な危険度の高いメソッドを呼び出せるということは、実際にユーザーがjava.lang.ProcessBuilderを呼び出す可能性を示唆します。Jandroidでは、このような脆弱性を検出するために以下のような方法を用います。

図1. Jandroidを使ったコード検査方法1.1

図1の「ProcessBuilder」メソッドは、ユーザーがテンプレートに指定した検査対象のメソッドです。Jandroidは、テンプレート上で検査対象のメソッドを取得し、アプリケーション内の該当のメソッドを含んだコードを検査し、結果を保存します。アクティビティが該当のメソッドを呼び出し可能かどうかを検査するために、ユーザーがテンプレートで指定したメソッドを始点とし、その始点を直接呼び出す相互参照を検出します。

図2. Jandroidを使ったコード検査方法1.2

図2の「Activities」は、ユーザーがテンプレートに指定した検査対象のアクティビティです。テンプレートからJandroidが探索するアクティビティの属性情報を読み、アプリケーションで検査した属性と一致するアクティビティを保存します。その後、上記の手順で検出した相互参照の経路がアプリケーション内のアクティビティまでつながるか検証します。もし相互参照の経路がアクティビティまで到達すれば、アクティビティが実行され、ProcessBuilderメソッドが呼び出されます。このように相互参照を繰り返し検査し、アクティビティを呼び出せる経路を見つけ出すことで、潜在的な脆弱性を検出します。

また、上の図1に示した単一のメソッド呼び出しだけでなく、アクティビティから呼び出される一連のコーディングパターンを検査することもできます。あるメソッドが別のメソッドと同時に呼び出されると、セキュリティ上の問題を引き起こすことが度々あります。例えば、WebViewのloadUrlとaddJavascriptInterfaceメソッドが同時に呼び出されるコードパターンがあります。このパターンに従ったコードフローがアクティビティに至ると、WebViewに追加された「ネイティブブリッジ」を攻撃者が自由に利用できるようになる可能性があります。

図3. Jandroidを使ったコード検査方法2

図3は、このコードパターンを見つける方法を示している。複数のメソッドが呼び出されることで脆弱性を引き起こす可能性がある地点を始点とし、ユーザーが呼び出すことができる最後のアクティビティまで検査することで、脆弱性のあるコードを検出します。例えば、addJavascriptInterfaceメソッドを探索して、その結果のクラス名を保管します。そして、テンプレートで定義されている始点となるloadUrlメソッドを、先に保管したクラス名と組み合わせて、同じクラスがloadUrlメソッドを使っているかどうか調べます。loadUrlメソッドが使用中の場合、メソッドの相互参照を再帰的に検査します。図2と同様に、相互参照で見つけた経路がユーザーがテンプレートに指定したアクティビティまで呼び出すことができるかを繰り返して行います。  

このようにして検査を実施した結果パターン化されたコードが検出された場合、そのアプリケーションはユーザーがセキュリティ上の脅威が存在するコードまで実行できるということを意味し、直接的に脆弱性につながる可能性が高くなります。

Jandroidを採択した理由

Androidの脆弱性検査自動化ツールとしてJandroidを採択した理由は、ユーザーが検出したい脆弱なコーディングパターンを自由に定義できるためです。ほとんどのAndroidアプリで発生する脆弱性とロジックバグは、アプリケーションの機能によって変化することが度々あります。アプリケーションごとに発生する現象が異なりますが、それぞれのアプリケーションでは同じ現象が頻発しがちです。さまざまなアプリケーションの脆弱なコーディングパターンを検出するために、個別にコードを検査するのでは非常に時間がかかってしまいます。そのため、セキュリティ診断を行うアプリケーションの特徴を把握して脆弱性やロジックのバグを引き起こしたコーディングパターンをテンプレート化することで、各テンプレートの結果を見ながら検査できるので、容易に脆弱性の高いコードを検出でき、検査時間を短縮できます。また、Androguardはコンパイル済みのコードを解析するため、APKファイルだけで簡易に検査できるというメリットがあります。

これらの理由から、LINEの多くのAndroidアプリにJandroidが適していると考えました。なお、ZDIで開催された「Mobile Pwn2Own」というハッキングコンテストにおいて、F-Secure LabsがJandroidを使って脆弱性のあるコードを検出した事例を発表しています。これは、ある企業のモバイル端末が持つ複数のバグを組み合わすことで、ユーザーのスマホをハッキングした事例です。攻撃に使用されたさまざまな脆弱性の内、ノート関連のアプリの脆弱性(CVE-2018-10501)についてはJandroidを使用することで簡単に検出できたそうです。

テンプレートファイルの構成

前述したように、Jandroidではユーザーが定義したコーディングパターンを検出するためにテンプレートファイルを使用します。このテンプレートファイルで検出したい脆弱なコーディングパターンを定義することができます。テンプレートファイルは、/templates/android/*.templateファイルで保存し、呼び出します。当該ファイルは、以下のようにJSONフォーマットで構成されます。

テンプレートファイル

{
    "METADATA": {
        "NAME": "JSbridgeBrowsable"
    },   
    "MANIFESTPARAMS": {
        "BASEPATH": "manifest->application->activity OR manifest->application->activity-alias",
        "SEARCHPATH": {
            "intent-filter": {
                "action": {
                    "LOOKFOR": {
                        "TAGVALUEMATCH": "<NAMESPACE>:name=android.intent.action.VIEW"
                    }
                },
                "category": {
                    "LOOKFOR": {
                        "TAGVALUEMATCH": "<NAMESPACE>:name=android.intent.category.BROWSABLE"
                    }
                },
                "data": {
                    "RETURN": ["<NAMESPACE>:host AS @host", "<NAMESPACE>:scheme AS @scheme"]
                }               
            }
        },
        "RETURN": ["<smali>:<NAMESPACE>:name AS @activity_name"]
    },
    "CODEPARAMS": {
        "SEARCH": {
            "SEARCHFORCALLTOMETHOD": {
                "METHOD": "Landroid/webkit/WebView;->addJavascriptInterface",
                "RETURN": "<class> AS @web_view"
            }
        },
        "TRACE": {
            "TRACEFROM": "<method>:@web_view[]->loadUrl(Ljava/lang/String;)V",
            "TRACETO": "<class>:@activity_name",
            "TRACELENGTHMAX": 10,
            "RETURN": "<tracepath> AS @tracepath_browsablejsbridge"
        }
    },
    "GRAPH": "@tracepath_browsablejsbridge WITH <method>:<desc>:<class> AS attribute=nodename"
}

上記のコードを簡単に説明します。

  1. METADATA  →  NAME にテンプレート名を指定します。
  2. MANIFESTPARAMS は、探索するアクティビティを定義するノードで、図2の「Activities」に相当します。AndroidManifest.xmlファイルには、探索対象のアクティビティのスコープが定義されています。配下の BASEPATH の値は、AndroidManifest.xmlファイルの <manifest><application><activity> のXMLタグ内で SEARCHPATH ノードと一致するアクティビティを探索することを意味します。 
  3. SEARCHPATHノードで は、 <intent-filter> 内の <action> タグで android:name が android.intent.action.VIEW の値や、 <category> タグで android:name が <NAMESPACE>:name=android.intent.category.BROWSABLE の値を探索します。一致するアクティビティがある場合、そのアクティビティ名を activity_name というテンプレート変数で保存します。
  4. CODEPARAMS は、探索するメソッドを定義するノードで、図3で探索するメソッドに相当します。 SEARCH ノードの SEARCHFORCALLTOMETHOD では、メソッドの値に定義されているクラスとメソッドを探索し、検出したクラスを RETURNの @web_view テンプレート変数に保存します。
  5. TRACE ノードは、Jandroidで探索する始点と終点を定義します。始点は、 TRACEFROM で、終点は TRACETO で定義します。図3で探索した後、探索をスタートする箇所と、図2で終点のアクティビティが、このノードに相当します。 TRACEFROM では、上記の SEARCH ノードで探索し、 web_view テンプレート変数に保存したクラスと loadUrl メソッドを組み合わせて始点として定義します。終点の TRACETO は、先の手順で検出した activity_name テンプレート変数のクラスとして定義します。つまり、このテンプレートは図2のコードのパターンを定義したものです。

実行する

python3でJandroidツールをコマンドラインから実行すると、多数のデバッグメッセージとともに解析中のメソッドなどの情報が出力されます。検出結果は/output/raw/*.jsonに保存され、コマンドラインで入力した-gオプション引数に応じて/output/graph/jandroid.htmlに生成されたグラフを確認することができます。オプション引数の詳細は、-hオプションで確認できます。

Jandroidの使用ログ

Jandroid> python3 src/jandroid.py -f /workspace/bin/apks/target/ -g visjs

----------------------------
            JANDROID
----------------------------
  
INFO     Creating template object.
INFO     1 potential template(s) found.
DEBUG    Parsing /Jandroid/templates/android/sample.template
INFO     Initiating Android analysis.
INFO     Performing basic checks. Please wait.
INFO     Basic checks complete.
INFO     Beginning analysis...
DEBUG    1 app(s) to analyse, using 2 thread(s).
DEBUG    Created worker process 0
DEBUG    Created worker process 1
DEBUG    AnalyzeAPK
DEBUG    Analysing without session
INFO     Analysing test.apk in worker thread 0.
DEBUG    AXML contains a RESOURCE MAP
DEBUG    Start of Namespace mapping: prefix 38: 'android' --> uri 105: 'http://schemas.android.com/apk/res/android'
DEBUG    START_TAG: manifest (line=2)
DEBUG    found an attribute: {http://schemas.android.com/apk/res/android}versionCode='b'19010402''
...
DEBUG    Parsing instructions
DEBUG    Parsing exceptions
DEBUG    Creating basic blocks in L$r8$java8methods$utility$Boolean$hashCode$IZ;->hashCode(Z)I [access_flags=public static synthetic] @ 0x18341c
DEBUG    Settings basic blocks childs
DEBUG    Creating exceptions
...

実行後、/output/graph/jandroid.htmlに生成された結果グラフは下図4のとおりです。Jandroidのテンプレートファイルに定義されているメソッドを始点として、コールフローが終点のアクティビティまでつながっていることがわかります。このグラフの接続情報は、Jandroidの実行終了時に、/output / raw / <App Name> .jsonに保存され、グラフ作成時に使用されます。

図4. Jandroidの結果グラフ

Jandroidの制限と改善方法

LINEのAndroidアプリにJandroidを適用したところ、あらかじめテンプレートで定義した脆弱なコーディングパターンは検出できませんでした。検出できない原因として、Jandroidにはいくつかの制限があることがわかったため、改善を試みました。

異なるクラスから呼び出されるパターンは検出されない問題

Jandroidが、2つの異なるメソッドを呼び出す脆弱なコーディングパターンを検出した場合、その2つのメソッドは異なるクラスから呼び出されたにもかかわらず、最終的に同じルート経路から呼び出されたコーディングパターンに検出に失敗するケースがありました。たとえば、下図5の構造のように、addJavaScriptInterfaceメソッドとloadUrlメソッドが異なるクラスから呼び出されると、同じルート経路で呼び出されていても検出されませんでした。

図5. Jandroidで検出できないコーディングパターン

  図5では、「Some Class」メソッドがBクラスとCクラスの異なるメソッドを呼び出しています。Class BのloadUrlメソッドとClass CのaddJavaScriptInterfaceメソッドのように異なるメソッドを呼び出すパターンを検出するようにテンプレートファイルで定義した場合、Jandroidは以下の手順で探索を行います。

addJavscriptInterface メソッドを探索した結果、検出したクラス(上記のサンプルではClass B)をテンプレート変数に保存します。そして、クラスが代入されているテンプレート変数と探索を始める loadUrl メソッドを組み合わせて始点として探索を開始します。つまり、図5と同じコードのパターンの場合、 addJavascriptInterface メソッドを使用するClass Bを検出しますが、その後始点から探索を開始する際は loadUrl メソッドがClass Bに含まれていると仮定するため、実際のClass Cにある loadUrl メソッドは検知されなくなります。Jandroidでは、 addJavascriptInterfaceメソッドと loadUrl メソッドが同じクラスで呼び出されると仮定するため、図5のようなコーディングパターンを検出できません。

改善方法

上記の問題を解決するために、異なるクラスで呼び出すメソッドのコールパターンを検出できるように以下のような方法で改善しました。

図6. 異なるクラスを検出する改善方法

ユーザーが探索対象のメソッドを入力できるように、テンプレートのTRACEFROM値にWITH演算子を扱う機能を実装しました。このWITH演算子は、オペランドの位置で定義されたメソッドを探索することで、相互参照を再帰的に探索します。相互に重なる経路がある場合、アクティビティのクラスやメソッドの始点から終点までの経路を探索します。図6のように「addJavascriptInterface WITH loadUrl」でTRACEFROM値を設定すると、2つのメソッドの相互参照先が同じ経路を検出できます。それから、この経路から終点であるアクティビティまでの探索を行います。

また、Jandroidを使ってメソッド同士の経路を探索するときも、ここで実装した機能で改善することができました。TRACEFROMとTRACETOがメソッドだとすると、2つのメソッドの経路を探索し見つかった重なった経路を中心点として、それぞれ残りの経路をつないで2つのメソッドの呼び出し経路を探索し、表現できるように実装しました。

一部のメソッドで相互参照が検出できない問題

Jandroidは、脆弱なコーディングパターンを検出するために相互参照を探索します。しかし、この探索方法だけでは、Android上のすべてのメソッドの相互参照は検出できません。下図のようにFragmentが作成された場合を例にしてみましょう。

図7. Fragmentのコールフロー

Fragmentが生成されると、onAttachから始まり、onCreate、onCreateViewの順にコールバック関数が呼び出されます。これらのメソッドは、アプリケーションコードではなく、Androidシステムから呼び出されるため、アプリケーションコード内でこれらのメソッドの相互参照を検出することはできません。Fragmentは、Androidアプリの画面切り替えに使用されますが、切り替えの際には、Androidシステムは画面リソースに格納されているクラスのビュー(view)コールバック関数を呼び出します。そのため、アプリケーションコードでFragmentが使用されている場合は、メソッドコールバックの相互参照が検出できないのです。つまり、現在Jandroidが使用しているメソッド間の相互参照による探索方法には限界があるのです。

Jandroidでは、このようなコールバック関数を検出するために、例外処理を追加しています。相互参照の再帰探索中に、例外処理に相当するメソッドを検出すると、メソッド名を変更するように実装されています。たとえば、コールバックで呼び出される onAttach を探索する際には、 onCreate にメソッド名を変えます。このように相互参照がないメソッドを onAttach  →  onCreate のように変更することで、メソッドを探索できるようにします。しかし、例外処理を使用しても、同じクラスでコールバックにより呼び出されるメソッドに限って名前を変更するだけなので、やはり限界があります。たとえば、 onAttach のようにクラスで一番最初に呼び出されるメソッドを探索する場合には、例外処理を使っても検出できませんでした。そのため、 NavController や Fragment など、画面切り替え機能や他のAndroidシステムで呼び出すメソッドは検出できませんでした。

改善方法

Androidシステム上で呼び出されたメソッドは、クロスリファレンスを再帰的にトラバースしてパスを見つけることができません。前述したAndroidのFragmentやNavControllerは、アプリ内での画面切り替えを役割を持ちます。相互参照で検出できないコードで実行フローが変わるので、検出を可能にするため次のように探索方法を改善しました。

探索開始前に、Androidアプリ内の画面切り替えに使用するリソースを抽出し、それに関連するFragment情報を解析します。また、アプリケーションパッケージ内のメソッドが該当のリソースを使用しているかどうかを検査し、使用している場合はメソッド、リソース、Fragment情報を保存します。その後、パターンを探索中にonCreateViewなどのメソッドに到達した場合には、保存されているFragment情報とクラスが一致するかどうかを検査します。またさらに、メソッド名を変更してメソッドをつなげる例外処理を追加しました。onCreateView => onViewCreatedのように、同一クラス内で関連性のあるメソッド名を変更する例外処理です。

コードフローを追う難しさ

Jandroidの検出結果のグラフには、始点と終点のクラス名とメソッド名が表示されます。しかし、検出結果を検証する際には、下図8のような結果だけでは、始点から終点までのコードフローを追うことは困難です。

図8. 改善前の結果グラフ

改善方法

探索の始点から終点までの経路全体を確認できるように、検出結果と結果グラフを改善しました。下図9は、経路全体を確認できるように改善した後の結果グラフです。

図9. 改善後の結果グラフ

LINEのAndroidアプリに適用した結果

この記事では、その中から1つの事例を紹介します。脆弱性を検出するために使用したテンプレートは以下のとおりです。

使用したテンプレートファイル

{
    "METADATA": {
        "NAME": "JSbridgeBrowsable"
    },   
    "MANIFESTPARAMS": {
        "BASEPATH": "manifest->application->activity OR manifest->application->activity-alias",
        "SEARCHPATH": {
            "intent-filter": {
                "action": {
                    "LOOKFOR": {
                        "TAGVALUEMATCH": "<NAMESPACE>:name=android.intent.action.VIEW"
                    }
                },
                "category": {
                    "LOOKFOR": {
                        "TAGVALUEMATCH": "<NAMESPACE>:name=android.intent.category.BROWSABLE"
                    }
                },
                "data": {
                    "RETURN": ["<NAMESPACE>:host AS @host", "<NAMESPACE>:scheme AS @scheme"]
                }               
            }
        },
        "RETURN": ["<smali>:<NAMESPACE>:name AS @activity_name"]
    },
    "CODEPARAMS": {
        "SEARCH": {
            "SEARCHFORCALLTOMETHOD": {
                "METHOD": "Landroid/webkit/WebView;->addJavascriptInterface",
                "RETURN": "<method> AS @web_view"
            }
        },
        "TRACE": {
            "TRACEFROM": "<method>:@web_view[] WITH Landroid/webkit/WebView;->loadUrl(Ljava/lang/String;)V",
            "TRACETO": "<class>:@activity_name",
            "TRACELENGTHMAX": 10,
            "RETURN": "<tracepath> AS @tracepath_browsablejsbridge"
        }
    },
    "GRAPH": "@tracepath_browsablejsbridge WITH <method>:<desc>:<class> AS attribute=nodename"
}

loadUrl と addJavascriptInterface を呼び出す脆弱なパターンのため、前述の WITH演算子 を使用しました。このパターンで検知した結果は以下のとおりです。

検出された結果グラフ - 図10 

図10の検出結果を確認すると、アクティビティからテンプレートで定義されているWebView loadUrlとaddJavascriptInterfaceメソッドを呼び出すメソッドまでの経路が確認できます。上記の結果グラフを参照して、検索した経路を並べると以下のようになります。

呼び出し順番

MainActivity->onNewIntent => AppSchemeInterpreter->maybeHandleSchemeIntent => AppSchemeInterpreter->interpret => AppSchemeInterpreter->interpretPayment => WebViewFragment->onCreateView

アプリケーションコードの経路をもとに解析すると、intent属性のandroid.intent.category.BROWSABLEを持つMainActivityアクティビティから始まり、WebViewFragment → onCreateViewメソッドに到達します。WebViewFragment -> onCreateView メソッドは、 WebView loadUrl と addJavascriptInterface メソッドを呼び出すコーディングパターンを持っていることが確認できました。

下図11は、実際のLINE Androidアプリをデコンパイルした後のコードフローです。Jandroidの結果と同じ経路でメソッドのフローをたどっていくと、onNewIntent → maybeHandleSchemeIntent → interpret → interpretPayment → onCreateViewの順で呼び出されていることがわかります。

図11. アプリケーションをデコンパイルしたコードの結果1

上図11において、メソッドが使用する引数は次のとおりです。 maybeHandleSchemeIntentは、onNewIntentとして受け取ったintentをstringに変換してinterpretを呼び出します。呼び出されたinterpretでは、Uri.parseメソッドを呼び出してインテントを解析してUriオブジェクトとして格納し、Uriオブジェクトのスキーム値を検査します。スキーム値が検査した値と一致した場合、interpretPaymentが呼び出されます。interpretPaymentは、Uriオブジェクトからurlパラメータによって解析されたデータを持つNavigationオブジェクトを生成します。生成されたNavigationオブジェクトは、以降interpretメソッドでnavController.navigateメソッドの引数として使用され、urlパラメータはWebViewFragmentArgsのonCreateViewメソッドの引数として使用されます。

図12. アプリケーションをデコンパイルしたコードの結果2

上図12のWebViewFragmentArgsのonCreateViewでは、webBridge → addJavaScriptInterfaceメソッドを呼び出すattackWebviewが呼び出され、WebViewFragmentArgs → loadUrlメソッドを呼び出すrenderWebPageが呼び出されていることがわかります。また、loadUrlメソッドを呼び出す引数を確認すると、WebViewFragmentArgsのonCreateViewメソッドのargs.getUrl()の値、つまり先述のinterpretPaymentメソッドから送ったurlパラメータがloadUrlメソッドの引数として呼ばれていることがわかります。

これらをまとめて、攻撃者の立場から攻撃コードを書くと次のようになります。ブラウザでは、intentデータであるscheme値とpath、parameterを「scheme://payment?url=https://attacker.com」に設定します。ユーザーがこのリンクにアクセスすると、アプリケーションが起動し、JavaScriptのメソッドにバインディングされているWebViewで 「https://attacker.com」というランダムな攻撃者サイトが起動します。攻撃者は、この攻撃者サイトを使うことでユーザーに対し悪意のある攻撃を仕掛けることができるのです。

実際、ユーザーのトークンを取得できるアプリケーションのJavaScriptメソッドがあり、攻撃者にユーザーのトークンを奪われる恐れがありました。結果的には、コーディングパターンを改善したJandroidで検査したところ、Androidアプリが画面の切り替えに使う経路を検出し、脆弱性のあるコーディングパターンを発見できました。

おわりに

ここまで、改良したJandroidをLINEのAndroidアプリに適用することで、脆弱性を検出した方法について紹介してきました。今回の記事で紹介した脆弱性の事例だけでなく、セキュリティ検査で発見した事例を継続的にテンプレートに追加することで、より多くの脆弱性をより短時間で検出できるようになります。

もちろん、Jandroidによるセキュリティ検査にも欠点はあります。それは、ユーザーが定義したテンプレートに対していのみ脆弱なパターンを発見することです。入力が実際のメソッドに到達するか解析する「Taint解析」を行わないため、テンプレートで定義した脆弱なコーディングパターンが存在してもユーザーの入力によってコードフローが変わってしまいます。その場合、目的の動作や結果が得られなかったり、特定の条件文によって脆弱なコーディングパターンにたどり着けない「偽陽性」の結果が出てしまうケースがあります。

ただし一方で、これらのツールの長所と短所を活かして適切に活用すれば、既知の脆弱性パターンを検出するまでの時間を短縮でき、テンプレートに脆弱性パターンを定義して自動で実行することで脆弱性の見逃しを防ぐこともできます。最終的には、複数のAndroidアプリをより簡単に検査できるようになるので、うまく活用すればセキュリティ検査担当者にもメリットがあります。今回の記事は以上となります。長文にもかかわらず、最後までお読みいただきありがとうございました。