Shoeisha Technology Media

CodeZine(コードジン)

記事種別から探す

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

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

  • LINEで送る
  • このエントリーをはてなブックマークに追加

 AndroidアプリにはSQLiteを使用する方法がいくつか用意されていますが、これらの挙動を十分に理解していないと思わぬ脆弱性を作りこんでしまう可能性があります。本稿ではこのバックグラウンドと正しい使い方のガイドラインを紹介します。

目次

はじめに

 Androidアプリケーションを作成する上でSQLiteを使用してデータベースを扱うことは多々あります。データの永続化や検索といった処理を容易に実装することができるので、多くのアプリケーションで使用されています。しかし、AndroidにはSQLiteを使用するための方法が以下のようにいくつか用意され、それぞれファイル作成時のパーミッションの挙動が異なっています。

  • SQLiteDatabase#openOrCreateDatabaseを使用して作成する
  • Context#openOrCreateDatabaseを使用して作成する
  • SQLiteOpenHelperクラスを使用して作成する

 もし、開発者がこれら方法の挙動を十分に理解していない場合、知らずのうちに脆弱性を作り込んでしまいます。

 実際に、いくつかのアプリケーションではSQLiteDatabase#openOrCreateDatabaseを起因とするファイルパーミッションに関する脆弱性が発見されています。

 Androidのアプリケーションは、基本的に他のアプリケーションで管理されているファイルにはアクセスできません。しかし、方法によっては他のアプリケーションからもアクセスできるファイルが作成されてしまいます。今回はこれらDBファイルを作成する方法について、それぞれDBファイルのパーミッションはどのようになっているのか、その挙動について解説します。

SQLiteDatabase#openOrCreateDatabase

 まず、SQLiteDatabase#openOrCreateDatabaseですが、以下のサンプルコードではdatabasesディレクトリ以下にapp.dbというファイル名でDBファイルが作成されます。

SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(new File(
    "/data/data/" + getContext().getPackageName() + "/databases/",
    "app.db"), null);

 作成されたDBファイルのパーミッションを確認すると644となっており、他のアプリケーションからもアクセスできるようになっています。では、実際にこのメソッドの内部ではどのようなことが行われているのでしょうか。

 openOrCreateDatabaseメソッドの内部ではopenDatabaseメソッドが呼ばれています。

SQLiteDatabase#openOrCreateDatabaseの中身
/**
 * Equivalent to openDatabase(path, factory, CREATE_IF_NECESSARY).
 */
public static SQLiteDatabase openOrCreateDatabase(String path,  CursorFactory factory) {
    return openDatabase(path, factory, CREATE_IF_NECESSARY);
}

省略 ...

public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
    return openDatabase(path, factory, flags, new DefaultDatabaseErrorHandler());
}

省略 ...

public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,
    DatabaseErrorHandler errorHandler) {
    SQLiteDatabase sqliteDatabase = openDatabase(path, factory, flags, errorHandler,
        (short) 0 /* the main connection handle */);

省略 ...

private static SQLiteDatabase openDatabase(String path,
    CursorFactory factory, int flags,
    DatabaseErrorHandler errorHandler, short connectionNum) {
    SQLiteDatabase db = new SQLiteDatabase(path, factory, flags,
        errorHandler, connectionNum);
    try {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.i(TAG, "opening the db : " + path);
        }
        // Open the database.
        db.dbopen(path, flags);
        db.setLocale(Locale.getDefault());

 openDatabaseメソッドではネイティブメソッドのdbopenが呼ばれ、その中でSQLiteの関数の一つであるsqlite3_open_v2関数を使用してDBファイルが作成されるようになっています。

android_database_SQLiteDatabase.cppの中身
/* public native void dbopen(String path, int flags, String locale); */
static void dbopen(JNIEnv* env, jobject object, jstring pathString, jint flags)
{

省略 ...

    err = sqlite3_open_v2(path8, &handle, sqliteFlags, NULL);
    if (err != SQLITE_OK) {
        LOGE("sqlite3_open_v2(\"%s\", &handle, %d, NULL) failed\n", path8, sqliteFlags);

 この付近のコードを確認する限り、作成されるファイルのパーミッションを設定したり変更したりという処理は見当たりません。よってデフォルトのumaskで作成され、その結果、ファイルのパーミッションは644になっているのではないかと推測します。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

修正履歴

  • 2012/06/22 18:05 「おまけ」の解説を一部アップデートしました。

著者プロフィール

バックナンバー

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

もっと読む

All contents copyright © 2005-2017 Shoeisha Co., Ltd. All rights reserved. ver.1.5