JSSECが公開している『Androidアプリのセキュア設計・セキュアコーディングガイド』の2016-09-01版を共有用にまとめているもののうち、「4.5. SQLite を使う」のものとなります
詳細やサンプルコードについては原著の方を参考ください
なお、直接外部から読み書きを許すデータベースは想定せず、ContentProviderのバックエンドやアプリ単体での仕様を前提としています
個人的な感想ですが、この項目は、一定レベルまでの第三者の攻撃から守る対策しか乗っていません
もしセンシティブな情報を扱う場合は、DBを扱うセキュリティ全般についての対策も見ておいた方が良いと思われます
チェックポイント
- SQLiteOpenHelperを使用している
- ただし、適切な配布場所、アクセス権が設定されている(後述)
- 入力値をSQL文に使用する場合にはプレースホルダを利用している
- アプリ要件に従って入力値をチェックしている
- 他アプリとのDBデータを共有する場合は、ContentProveiderでアクセス制御している
Tips
DBのファイル配置場所、アクセス権について
アクセス権が適切であっても、SQLiteOpenHelperの第2引数にSDカードの絶対パスを指定するなど、アクセス権の設定を行えない場所に配置した場合、外部からアクセス可能になります
また、アプリディレクトリに配置しても、アクセス権が正しくない場合、意図しないアクセスになります
そのため下記2点が必要になります
- Context#getDatabasePath(String name)、もしくはContext#getFilesDirで取得できるディレクトリに配置する
- MODE_RIVATEに設定する
SQLiteOpenHelperを使用した場合、コンストラクタの引数にDBの名前を指定すれば、問題はありません。ただし、引数にフルパスを指定した場合、その場所に作成されてしまい、場所によってはアクセス可能になってしまうため、注意が必要です
Context#openOrCreateDatabaseを使用する場合は、明示的にMODE_PRIVATEを指定する必要があります。ファイルの配置場所に関してはSQLiteOpenHelperと同様です
プレースホルダについて
SQLインジェクションを防ぐために、任意の入力値をSQL分に組み込む際にはプレースホルダを利用すべきです。下記の2つの方法があります
- SQLiteDatabase#compileStatement()を使用して SQLiteStatementを取得する。その後、SQLiteStatement#bindString()、bindLong()などを使用してパラメータをプレースホルダに配置する(ただし、SELECTコマンドの結果として先頭の1要素しか取得できないため、用途が限られます)
- SQLiteDatabeseクラスのexecSQL()、insert()、update()、delete()、query()、rawQuery()、replace()などを呼び出す際にプレースホルダを持ったSQL 文を使用する
ただし、テーブルの作成や削除等のDBオブジェクトを処理対象としたSQL文はテーブル名などの値に対してプレースホルダを使用できません。そのため、プレースホルダの使用できない値に対して、外部から入力された任意の文字列を使用するような設計はすべきではなく、また、入力値に危険がないどうか確認する必要があります
DBのオープンの仕方について
読み込みのみの場合に関しては、SQLiteDatabase#openDatabaseにOPEN_READONLYを指定して、DBをオープンするのが好ましいです
SQLiteOpenHelper#getReadableDatabase、getWritableDatabaseやContext#openOrCreateDatabase、QLiteDatabase#openOrCreateDatabaseでオープンした場合は、読み書き可能な状態で開かれるため、アプリの仕様と実装の範囲で対応できますが、書き換えられる可能性が存在します。
入力性データの妥当性をチェックする
SQLiteは値の正当性確認については期待できません。なので、アプリの要件にしたがってSQL文を使用して値を格納、取得する前に、内容の型や長さについて確認する必要があります
DBにいれるデータについて
SQLiteでは
- 全てのデータが平文の文字データとしてDBファイル何に格納されます
- DBに対してデータの削除を行っても、データ自体はDBファイルから削除されません
- データを更新した場合も、DBファイル内には更新前のデータも残ってます
そのため、削除されたはずのデータが残っている可能性があります。基本的には、対策をしていれば直接アクセスされません。が、root権限を奪取されている場合等はファイルを抜き出せるため、センシティブなデータはそのまま格納すべきではありません
もし、どうしても格納する場合は、暗号化したデータを格納する、DB全体を暗号化するなどの対策が必要です
参考
『Android アプリのセキュア設計・セキュアコーディングガイド』【2016年9月1日版】
https://www.jssec.org/dl/android_securecoding.pdf