LAC WATCH

セキュリティとITの最新情報

RSS

株式会社ラック

メールマガジン

サイバーセキュリティや
ラックに関する情報をお届けします。

ラックピープル | 

モバイルアプリ開発時に注意!アクセス制限不備の脆弱性と対策

こんにちは、デジタルペンテストサービス部の小松です。
企業が利用するITシステムに疑似攻撃を仕掛け、サイバー攻撃に対する弱点を発見する「ペネトレーションテスト」や、モバイルセキュリティのリサーチを担当しています。

近年、モバイルアプリケーション(以下、モバイルアプリ)のアクセス制限不備による脆弱性が、JVN(Japan Vulnerability Notes)にて頻繁に公開されています *1。しかし、モバイルアプリに本脆弱性を作り込まないための、実装に関する技術的な解説記事はあまり見受けられません。

*1 JVN iPedia - 脆弱性対策情報データベース

そこで本記事では、アクセス制限不備の中でも特に多い「ディープリンクを使用してリクエストされた、任意のURLにアクセスしてしまう脆弱性」について解説します。Androidアプリのソースコードを例に、モバイルアプリ開発者向けの具体的な対策をご説明しますので、セキュアなモバイルアプリ開発の一助となれば幸いです。

使い慣れたモバイルアプリを経由するので騙されやすい

モバイルアプリに「ディープリンクを使用してリクエストされた、任意のURLにアクセスしてしまう脆弱性」が存在していると、攻撃者が当該モバイルアプリを経由した、任意のWebサイトへのアクセスを可能にする恐れがあります。

攻撃者がモバイルアプリに潜む脆弱性を悪用することで、開発者が意図しないフィッシングサイトなど悪意のあるWebサイトを、ユーザに開かせてしまいます。使い慣れたモバイルアプリはユーザにとって信頼性が高いため、騙されてしまう危険性があります。ユーザが悪意のあるWebサイトを開いてしまうと情報漏えいにつながる恐れがあるため、モバイルアプリの開発側でも対策を取るべきと考えられます。

現在開発しているモバイルアプリ、もしくはこれから開発するモバイルアプリに以下のような要件がある場合、脆弱性が作り込まれていないか、脆弱性が作り込まれる設計になっていないか、ぜひご確認ください。

  • ディープリンクを実装することにより、Webブラウザからモバイルアプリを起動する
  • WebViewを実装することにより、インターネット上のWebコンテンツを表示する

それでは、実際にソースコードと照らし合わせながら、脆弱性の実装や悪用シナリオや対策についてご説明します。

ディープリンクとは

モバイルアプリにおけるディープリンクとは、Webサイト上のリンクや他のモバイルアプリなどから、特定のコンテンツに直接アクセスさせる機能のことです。例えば、SNS上に掲載している商品リンクをタップしてショッピングアプリを起動し、該当する商品ページを表示させることができます。

ディープリンクにはOSによって、以下のような種類が存在します。

  • Custom URL Scheme
  • App Links(Android) / Universal Links(iOS)

各ディープリンクの違いについて詳細な解説は割愛しますが、Custom URL Schemeは悪意のあるモバイルアプリによって悪用される恐れがあるため、セキュリティの観点からはApp LinksやUniversal Linksを使用することが推奨されています*2。しかし、本記事で解説するアクセス制限不備の脆弱性に関しては、どちらのディープリンク手法を用いる場合においても作り込んでしまう可能性があり、App LinksやUniversal Linksならば安全というわけではないため注意が必要です。

*2 Apple Developer Documentation - Defining a Custom URL Scheme for Your App

Androidにおけるディープリンクの実装

まずAndroid Developers*3を参考に、実際にディープリンク(Custom URL SchemeおよびApp Links)を実装します。以下はAndroidManifest.xmlに追記した内容です。

*3 アプリ コンテンツ用のディープリンクを作成する | Android Developers

<activity android:name="jp.co.lac.deeplink.WebViewActivity">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:host="webview"
            android:scheme="lacapp" />
    </intent-filter>
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="http"
            android:host="*****.github.io"
            android:pathPrefix="/webview" />
    </intent-filter>
</activity>

これにより、以下2つのURIがWebViewActivityに変換されるようになります。

  • lacapp://webview
  • http://*****.github.io/webview

なお、本来であればWebViewActivityの追加やモバイルアプリをWebサイトに関連付ける処理が必要ですが、本記事では省略します。

正しくディープリンクを実装することができていれば、adb(Android Debug Bridge)コマンド*4を使用して、実際に直接WebViewActivityを呼び出すことが可能です。

*4 adb(Android Debug Bridge)はコマンドラインからAndroid端末と通信するための、多用途ツールです。Androidアプリのデバッグなどに使用します。

$ adb shell am start -a android.intent.action.VIEW -d lacapp://webview
or
$ adb shell am start -a android.intent.action.VIEW -d http://*****.github.io/webview

以下の図1は、adbコマンドを用いてWebViewActivityを呼び出した際の画像です。

図1 ディープリンクによるモバイルアプリの起動
図1 ディープリンクによるモバイルアプリの起動

アクセス制限不備の脆弱性

「ディープリンクを使用してリクエストされた、任意のURLにアクセスしてしまう脆弱性」は、ディープリンクによって受け取ったIntentに含まれているURLに、WebViewでアクセスするような実装のモバイルアプリによく見られます。

このような実装が求められるのは、例えばモバイルアプリ上でキャンペーンサイトを表示させたいなどという場合が考えられます。こうすることで、キャンペーンサイトを構築した際にモバイルアプリを改修することなく、SNS上のリンクなどから任意のキャンペーンサイトを表示できるためです。

しかし、セキュリティを考慮せずにこの機能を実装してしまうと、脆弱性を作り込んでしまう可能性があります。その実例を次でご紹介します。

脆弱性を作り込んでしまった実装の例

まずは、ディープリンクによって受け取ったIntentに含まれているURLに、WebViewでアクセスする機能を実装します。以下は、WebViewActivityクラスのonCreateメソッドの内容です。

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_webview);
    WebView webView = findViewById(R.id.webview);
    Intent intent = getIntent();
    Uri uri = intent.getData();
    String query = uri.getQueryParameter("url");
    webView.loadUrl(query);
}

ここでは、WebViewActivity起動時にIntentを受け取り、Intentに含まれているURIを取得しています。その後、URIのクエリストリングから、urlというパラメータの内容を取得し、WebViewで表示しています。

これにより、先ほどのadbコマンドにurlというパラメータを付与することで、urlに指定したURLをモバイルアプリのWebView上で開くことが可能となります。

$ adb shell am start -a android.intent.action.VIEW -d lacapp://webview?url=http://192.168.1.10/campaign.html
or
$ adb shell am start -a android.intent.action.VIEW -d http://*****.github.io/webview?url=http://192.168.1.10/campaign.html

以下の図2は、実際にadbコマンドを用いて正規のキャンペーンサイト(を模したWebサイト)を表示した際の画像です。

図2 ディープリンク経由によるWebViewの表示
図2 ディープリンク経由によるWebViewの表示

上記ソースコードの場合、ディープリンクに任意のURLを指定することで、開発者が想定していないWebサイトなどをモバイルアプリ上で表示できます。これこそがアクセス制限不備の脆弱性です。

考えられる脆弱性悪用のシナリオ

多くのモバイルアプリには認証機能のためのログイン画面が存在しています。このログイン画面を利用したフィッシングなどが、本脆弱性を悪用するシナリオとして考えられます。具体的な悪用シナリオの流れは、以下のとおりです。

1. 攻撃者は、脆弱なモバイルアプリの正規のログイン画面を模倣した偽のログイン画面を作成、公開します。

図3 偽のログイン画面
図3 偽のログイン画面

2. 攻撃者は、脆弱なモバイルアプリ上で偽のログイン画面を表示させるURIを作成し、SNSなどで拡散します(図はイメージ画像です)。

図4 ユーザのタップを促すSNS投稿
図4 ユーザのタップを促すSNS投稿

3. 脆弱なモバイルアプリの利用者が、SNS上のURIをタップすることでモバイルアプリが起動し、攻撃者が作成した偽のログイン画面が表示されます。

図5 モバイルアプリ上で表示された偽のログイン画面
図5 モバイルアプリ上で表示された偽のログイン画面

4. 脆弱なモバイルアプリの利用者が、正規のログイン画面と誤認しそのまま認証情報を入力することで、認証情報が攻撃者のサーバに送信され、漏えいしてしまいます。

対策

本脆弱性の対策は、外部から受け取ったURLをモバイルアプリのWebViewで表示する場合、表示可能なWebサイトを想定されているWebサイトに限定するという方法が考えられます。

例えば、アクセス可能なWebサイトの許可リストをモバイルアプリ内に予め保持しておき、外部から受け取ったURLが許可リスト内のURLと一致するか検証するといった方法です。以下は、簡易的な許可リスト実装時のres/values/array.xmlと、WebViewActivityクラスのonCreateメソッドの内容です。

<resourcesl>
    <string-array name="allow_url_list"l>
        <iteml>www.lac.co.jp</iteml>
    </string-arrayl>
</resourcesl>
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_webview);
    Context context = getApplicationContext();
    String[] allowList = getResources().getStringArray(R.array.allow_url_list);
    WebView webView = findViewById(R.id.webview);
    Intent intent = getIntent();
    Uri uri = intent.getData();
    Uri query = Uri.parse(uri.getQueryParameter("url"));
    for (String url : allowList) {
        if (query.getScheme().equals("https") && query.getHost().equals(url)) {
            webView.loadUrl(query.toString());
        } else {
            Toast.makeText(context, "指定されたURLは許可リストにありません", Toast.LENGTH_SHORT).show();
        }
    }
}

このような実装にすることで、モバイルアプリは攻撃者が作成した偽のログイン画面へアクセスできなくなり、開発者の想定したURLにのみアクセスが可能となります。以下は、簡易的な許可リスト実装後に、ディープリンク経由で偽のログイン画面を開こうとした際の画像です。

図6 許可リスト実装後に偽のログイン画面を開こうとした際の様子
図6 許可リスト実装後に偽のログイン画面を開こうとした際の様子

偽のログイン画面は許可リストにないため、アクセスできなくなっていることを確認できます。

おわりに

「ディープリンクを使用してリクエストされた、任意のURLにアクセスしてしまう脆弱性」は実装や対策について解説を行う記事が少なく、そもそも脆弱性として認識されていない場合も多いのではないかと思います。しかし、作り込まれやすい脆弱性であり、悪用された場合にはユーザの情報漏えいなどといった実害につながる恐れがあります。また、WebViewの実装によってはさらなる攻撃につながることもあり、より影響の大きい攻撃の入り口となる可能性もあるため注意が必要です。

ラックではモバイルアプリに潜む脆弱性を検出するセキュリティソリューションとして、「スマートフォンアプリケーション診断」や「Secure Coding Checker」といったサービスを提供しています。より強固なモバイルアプリ開発のために、これらのサービスの活用もご検討ください。

この記事は役に立ちましたか?

はい いいえ