中安拓也のブログ

プログラミングについて書くブログ。 Twitterやってます @l08084

【Cordova】【Android】 Webviewのキャッシュを消す

はじめに

ハイブリッドアプリフレームワークである、Ionic(Cordova)を使用してiOS/Androidのモバイルアプリを作成していたところ、下記のようなセキュリティに関する指摘を受けた。

<指摘内容>
Android端末でアプリを実行すると、端末の下記フォルダに、個人情報が含まれたキャッシュファイルが作成される。
/data/data/<パッケージ名>/cache/Webview/Default/HTTP Cache

上記で受けた指摘の解消、具体的にはキャッシュファイルを削除する方法について、サンプルアプリを例に説明する。

環境

  • cordova-plugin-ionic-webview 4.2.1
  • Android Studio 4.2 Beta 4

ionic infoコマンドの実行結果

$ ionic info

Ionic:

   Ionic CLI                     : 6.11.8 (/usr/local/lib/node_modules/@ionic/cli)
   Ionic Framework               : @ionic/angular 5.5.4
   @angular-devkit/build-angular : 0.1100.7
   @angular-devkit/schematics    : 11.0.7
   @angular/cli                  : 11.0.7
   @ionic/angular-toolkit        : 3.0.0

Cordova:

   Cordova CLI       : 8.0.0
   Cordova Platforms : android 7.0.0
   Cordova Plugins   : cordova-plugin-ionic-keyboard 2.2.0, cordova-plugin-ionic-webview 4.2.1, (and 4 other plugins)

Utility:

   cordova-res : not installed
   native-run  : not installed

System:

   ios-deploy : 1.9.2
   ios-sim    : 6.1.2
   NodeJS     : v12.13.1 (/usr/local/bin/node)
   npm        : 5.6.0
   OS         : macOS Catalina
   Xcode      : Xcode 12.0.1 Build version 12A7300

キャッシュファイルの確認方法

キャッシュファイルの削除方法について説明する前に、Webviewによって作成されるキャッシュファイルの確認方法について説明する。

キャッシュファイルの確認には、Android StudioのDevice File Explorerを使用できる。

  • Device File Explorerの開き方
    • Android Studioを開く
    • メニューの[View] -> [Tool Windows] -> [Device File Explorer]を選択

Android端末を持っていないのでエミュレーターを使用する。

アプリを実行すると、下記のように、/data/data/io.ionic.starter/cache/Webview/Default/HTTP Cache/Code Cache配下にキャッシュファイルが作成されていることがわかる。(io.ionic.starterは実行しているサンプルアプリのパッケージ名)

f:id:l08084:20210214175319p:plain
キャッシュファイルが作成されていることを確認できる

なお、Device File ExplorerはDevice File Explorerを開いた状態のファイルの状態を表示するだけで、最新のファイルの状態を表示してくれるわけではない。

ファイルの最新の状態を確認したいときは、対象のモバイル端末/エミュレーターで同じ端末を選択し直すとファイルの状態が最新化される。

f:id:l08084:20210220153658p:plain
再度同じ端末を選択すると、ファイルの状態が最新化される

そもそもキャッシュを作らないという手もある

これから、/data/data/<パッケージ名>/cache/Webview/Default/HTTP Cache 配下のキャッシュファイルの削除方法について説明していくが、モバイルアプリ側ではなく、API側の修正が可能ならば、そもそもキャッシュファイルを作らないように設定することもできる。

HTTPレスポンスにCache-Control: no-storeHTTPヘッダを登録することで、Webサーバから返されてくるコンテンツをキャッシュに記録することを禁止できるため、/data/data/<パッケージ名>/cache/Webview/Default/HTTP Cache 配下にキャッシュファイルが作成されなくなる。

もし、API側の改修が可能な状況なら、Cache-Control: no-storeHTTPヘッダを登録したほうがいちいちキャッシュファイルを削除するよりもスマートな対応になる可能性が高い。

キャッシュファイルの削除

キャッシュファイルの削除方法について説明していく。

「キャッシュファイルの確認方法」の章で確認したキャッシュファイルを削除する機能をアプリに追加するために、cordova-plugin-ionic-webviewを改修してカスタムプラグインを作成する。

なお、cordova-plugin-ionic-webviewはCordovaアプリでIonic CLIを使用した場合、デフォルトでインストールされるプラグインとなる。

カスタムプラグインの作成

まず、GitHubのcordova-plugin-ionic-webviewリポジトリをForkして別のリポジトリを作成する。

f:id:l08084:20210227145444p:plain
リポジトリをForkする

続いて、Forkして作成したリポジトリをローカルにgit cloneして、cordova-plugin-ionic-webview/src/android配下のIonicWebViewEngine.javaを開いて、下記の二つのメソッド(clearCacheFolderdestroy)を追加する。

import java.io.File;

// ...省略

  /**
   * キャッシュファイルを削除する処理。
   *
   */
  private void clearCacheFolder (File dir) {
    if (dir != null && dir.isDirectory()) {
      try {
        for (File child : dir.listFiles()) {
          if (child.isDirectory()) {
            clearCacheFolder(child);
          }
          child.delete();
        }
      } catch (Exception ex) {
        Log.e(TAG, "Failed to clean the cache, error", ex);
      }
    }
  }

  /**
   * アプリを閉じたときに呼び出されるライフサイクルメソッド。
   * キャッシュファイルの削除処理を呼び出している。
   *
   */
  @Override
  public void destroy() {
    super.destroy();
    File cacheDir = cordova.getActivity().getApplicationContext().getCacheDir();
    clearCacheFolder(cacheDir);
  }

上記のメソッドを追加した後に、変更内容をリポジトリにpushする。

既存のcordova-plugin-ionic-webviewはもう必要ないため、下記のコマンドで削除。

cordova plugin rm cordova-plugin-ionic-webview

代わりにForkしてメソッドを追加したリポジトリを下記のコマンドで追加する。(URLは参考として私のForkしたリポジトリのURLを載せている)

f:id:l08084:20210227151053p:plain
ForkしたリポジトリのURLをコピーして、 インストールを行う

$ cordova plugin add https://github.com/l08084/cordova-plugin-ionic-webview.git

動作確認

上記の改修したプラグインをエミュレーターで実行すると、アプリを閉じたタイミングで/data/data/io.ionic.starter/cache/Webview/Default/HTTP Cache/Code Cache配下のキャッシュファイルが削除されるようになっていることがわかる。

f:id:l08084:20210227170402p:plain
キャッシュファイルが削除されている

苦労した点

  • WebviewのclearCache(true)で上記のキャッシュファイルも削除してくれる認識でいたが違った
  • WebSettingsのsetAppCacheEnabled(false)を使えば、上記のキャッシュファイルを作成しないようになるかと思ったが違った
  • カスタムしたcordova-plugin-ionic-webviewをGitHubに上げずにローカルに配置した状態(custom_plugins/配下に配置した)で使用しようとしたが、Androidビルドするタイミングで下記のエラーが発生して、結局解決できなかった。リポジトリをForkしてGitHub経由でカスタムしたプラグインをインストールするようにしたら下記のエラーは解消した

ローカルにカスタムプラグインを配置した時に発生したエラー

Android Studio project detected
Discovered plugin "cordova-plugin-ionic-webview" in config.xml. Adding it to the project
Failed to restore plugin "cordova-plugin-ionic-webview" from config.xml. You might need to try adding it again. Error: Failed to fetch plugin file:custom_plugins/cordova-plugin-ionic-webview via registry.
Probably this is either a connection problem, or plugin spec is incorrect.
Check your connection and plugin name/version/URL.
Failed to get absolute path to installed module

参考サイト

重要情報の漏えいにつながるスマホアプリのキャッシュ問題と対策 | セキュリティ対策のラック

WebView  |  Android Developers

WebSettings  |  Android Developers

caching - Android Webview - Completely Clear the Cache - Stack Overflow

How can I read Chrome Cache files? - Stack Overflow

Cordova Web view cache clear in android - Stack Overflow

IPA ISEC セキュア・プログラミング講座:Webアプリケーション編 第5章 暴露対策:プロキシキャッシュ対策