SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Javaセキュアコーディング入門

AndroidアプリにおけるDBファイルの正しい使い方

Javaセキュアコーディング入門(5)


  • X ポスト
  • このエントリーをはてなブックマークに追加

Context#openOrCreateDatabase

 次に、Context#openOrCreateDatabaseですが、先のSQLiteDatabaseクラスのメソッドとは異なり、第一引数にはDBファイル名、第二引数は作成するファイルのパーミッション(モード)を指定します。

 以下のサンプルコードでは、databasesディレクトリ以下にapp.dbというファイル名でMODE_PRIVATEで作成され、DBファイルのパーミッションは660となります。

SQLiteDatabase db = this.getContext().openOrCreateDatabase("app.db",
    Context.MODE_PRIVATE, null);

 第二引数で指定できるモードは三種類あり以下のようになっています。

第二引数で指定できる3つのモード
説明
Context.MODE_PRIVATE 呼び出し元のアプリケーションのみ読み書き可
Context.MODE_WORLD_READABLE 他のアプリケーションも読み込み可
Context.MODE_WORLD_WRITEABLE 他のアプリケーションも書き込み可

 Context.MODE_PRIVATEを指定してファイルを作成するとパーミッションは660となり、他のアプリケーションからはアクセスできないDBファイルが作成されます。

 しかし、もしContext.MODE_WORLD_READABLEを指定するとパーミッションは664となり、他のアプリケーションからもアクセスできるようになります。Context.MODE_WORLD_WRITEABLEを指定した場合は662となり、他のアプリケーションから書き込みができるようになります。また、Context.MODE_WORLD_READABLEとContext.MODE_WORLD_WRITEABLEの両方を指定するとパーミッションは666となり、すべてのアプリケーションから読み書きできるファイルが作成されます。

 では、実際にこのContext#openOrCreateDatabaseではどのようなことが行われているのでしょうか。

Context#openOrCreateDatabaseの中身
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode,
    CursorFactory factory) {
    File f = validateFilePath(name, true);
    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(f, factory);
    setFilePermissionsFromMode(f.getPath(), mode, 0);
    return db;
}

 内部ではSQLiteDatabase#openOrCreateDatabaseを呼び出しています。しかし、その後にsetFilePermissionsFromModeと呼ばれる関数を使用し何かしら行っているわけですが、この関数内で、非公開APIのFileUtils#setPermissionsを使用して作成されたDBファイルのパーミッションを変更しています。

SQLiteOpenHelper

 先の2つのメソッドとは異なり、このSQLiteOpenHelperクラスはSQLiteを使用する際のヘルパークラスで、実際に使用する場合はこれを継承したクラスを作成し実装を進めていきます。このクラスを使用した場合、作成されるDBファイルのパーミッションは660となります。

 実際に内部の動作を確認してみると、

SQLiteOpenHelper#getWritableDatabaseの中身
public synchronized SQLiteDatabase getWritableDatabase() {

省略 ...

    boolean success = false;
    SQLiteDatabase db = null;
    if (mDatabase != null) mDatabase.lock();
    try {
        mIsInitializing = true;
        if (mName == null) {
            db = SQLiteDatabase.create(null);
        } else {
            db = mContext.openOrCreateDatabase(mName, 0, mFactory,
                           mErrorHandler);
        }

Context#openOrCreateDatabaseを使用し、作成するファイルのモードは0(MODE_PRIVATE)を指定してDBファイルを作成しています。このことから、SQLiteOpenHelperクラスでは作成されるDBファイルのパーミッションはMODE_PRIVATE固定ということが分かります。

まとめ

 このように、データベースを扱うそれぞれの方法にはDBファイルのパーミッションに関して挙動の違いがあります。もし、データベースにセンシティブなデータが保存されている場合、この挙動の違いを把握しないままアプリケーションを開発してしまうと、情報漏えいのおそれがあります。

 特別な理由がない限り、ファイルを作成する場合は以下の2点に留意してください。

  • Context#openOrCreateDatabaseを使用し、MODE_PRIVATEを指定してDBファイルを作成する
  • SQLiteOpenHelperクラスを使用してデータベースを扱う

 これらいずれかの方法でDBファイルへのアクセスを制限する必要があります。なお、Javaセキュアコーディングスタンダードにはファイルのパーミッションについて対応するルールがあります。

 こちらも併せて参照してください。

おまけ:ファイルのパーミッションを変更するには

 AndroidのAPIレベル9以降では、File#setReadableやFile#setWritableなどのファイルのパーミッションを変更するメソッドが用意されています。しかし、それ以前のバージョンではそのようなファイルのパーミッションを変更するメソッドは用意されていません。もし全てのバージョンに対応する場合は、ネイティブコードを書くか、またはリフレクションを使用して先のContext#openOrCreateDatabase内で使用しているような非公開APIのFileUtils#setPermissionsにアクセスし使用することになります。

Class<?> fileUtils = Class.forName("android.os.FileUtils");
Method setPermissions = fileUtils.getMethod("setPermissions",
        String.class, int.class, int.class, int.class);
int flag = (Integer) setPermissions.invoke(null, filename, permissions, -1, -1);

 リフレクションを使用するとクラスやメソッドの情報を取得したり実行したりすることができ、結果として非公開APIにアクセスすることも可能になります。Javaセキュアコーディングスタンダードには、リフレクションの使用に対応するルールがあるので参照してください。

参考資料

修正履歴

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
Javaセキュアコーディング入門連載記事一覧

もっと読む

この記事の著者

熊谷 裕志(JPCERTコーディネーションセンター)(クマガイ ヒロシ(JPCERTコーディネーションセンター))

情報セキュリティアナリスト JPCERTコーディネーションセンターベンチャ企業にてWEBサイトのデザインやシステム開発、Androidアプリケーションの開発などに従事したのち、2011年4月よりJPCERTコーディネーションセンターにて、脆弱性情報の分析やセキュアコーディングの普及活動に携わってい...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/6495 2012/06/22 18:05

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング