🎉
【Flutter】SQLiteのクエリパラメータの使い方と安全なデータベース操作
はじめに
データベース操作で最も重要なのは、安全性です。SQL インジェクション攻撃を防ぐため、適切なパラメータバインディングの使用方法を説明します。
基本的なパラメータバインディング
SQLite では?
を使ってパラメータをバインドします。
// 良い例:パラメータバインディングを使用
// データベースに新しいレコードを挿入する際、値を?でプレースホルダーとして指定
int recordId = await db.rawInsert(
'INSERT INTO my_table(name, year) VALUES (?, ?)',
['my_name', 2019]
);
// 悪い例:文字列結合を使用
// SQLインジェクションの危険性があるため、この方法は避ける
int recordId = await db.rawInsert(
"INSERT INTO my_table(name, year) VALUES ('my_name', 2019)"
);
IN 句でのパラメータバインディング
複数の値を含む IN 句を使用する場合の正しい方法を説明します。
IN 句とは?
IN 句は、複数の条件を指定して検索を行う場合に使用するクエリです。
例)
// 通常のWHERE句での書き方(OR を使用)
SELECT * FROM users
WHERE name = 'Taro' OR name = 'Jiro' OR name = 'Hanako';
// IN句を使用した場合(より簡潔に書ける)
SELECT * FROM users
WHERE name IN ('Taro', 'Jiro', 'Hanako');
// データベースから複数の条件に一致するレコードを取得
var list = await db.rawQuery(
'SELECT * FROM my_table WHERE name IN (?, ?, ?)',
['cat', 'dog', 'fish']
);
// 動的に条件の数が変わる場合は以下のように対応
List<String> inArgs = ['cat', 'dog', 'fish'];
var list = await db.query(
'my_table',
where: 'name IN (${List.filled(inArgs.length, '?').join(',')})',
whereArgs: inArgs
);
パラメータの位置指定
同じ値を複数回使用する場合は、位置パラメータを活用できます。
// ?1, ?2 のように数字で位置を指定
var result = await db.rawQuery(
'SELECT ?1 as item1, ?2 as item2, ?1 + ?2 as sum',
[3, 4]
);
// 結果: [{'item1': '3', 'item2': '4', 'sum': 7}]
NULL の扱い方
NULL の検索には特別な構文を使用します。
// 良い例:IS NULLを使用
var list = await db.query(
'my_table',
columns: ['name'],
where: 'type IS NULL'
);
// 悪い例:=を使用
// この方法では正しく動作しない
var list = await db.query(
'my_table',
columns: ['name'],
where: 'type = ?',
whereArgs: [null]
);
LIKE 句の使用例
テキスト検索でよく使用される LIKE 句の例を紹介します。
// 'Ta'で始まる名前を検索
var list = await db.query(
'my_table',
columns: ['name'],
where: 'name LIKE ?',
whereArgs: ['Ta%']
);
// 'free'を含む名前を検索
var list = await db.query(
'my_table',
columns: ['name'],
where: 'name LIKE ?',
whereArgs: ['%free%']
);
まとめ
- SQL インジェクション対策として、必ずパラメータバインディングを使用する
- IN 句を使用する場合は、動的にプレースホルダーを生成する
- NULL 値の検索には
IS NULL
を使用する - LIKE 句での検索では
%
を適切に使用する
これらの方法を使用することで、安全で効率的なデータベース操作が可能になります。
参照
Discussion