Node.jsを使用してSQLクエリを生成する際、適切な方法で実装しなければSQLインジェクションのリスクが高まります。
本記事では、プレースホルダーを活用し、安全かつ柔軟なWHERE句を作成する方法を詳しく解説します。
目次
SQLクエリの動的生成における課題
動的なSQLクエリを作成する場合、以下のような課題が発生することがあります。
- SQLインジェクションのリスク
- プレースホルダーの管理
- 複数の条件を適切に組み合わせる
- NULL値や配列の処理
特に、IN
句を使う場合に適切な実装を行わないと、意図しないデータ構造になり、エラーの原因となります。
WHERE句を安全に生成する関数
以下の関数は、Node.jsでSQLクエリのWHERE句を安全に生成するものです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
/** * WHERE句を作成する汎用関数 * @param {string} tableName - テーブル名 * @param {string} field - フィールド名 * @param {string} operator - 比較演算子 * @param {Array|string} addField - 追加のフィールド * @param {Object} queryParams - クエリパラメータ * @param {number} currentIndex - プレースホルダーのインデックス * @returns {Object|null} - クエリテキストとインデックスを含むオブジェクト */ const whereQuery = (tableName, field, operator, addField = [], queryParams, currentIndex) => { if (operator === 'IS NULL' || operator === 'IS NOT NULL') { return { text: `(${tableName}.${field} ${operator})` }; } const value = queryParams[field]; if (value === undefined || value === null || value === '') { return null; } if (operator === 'LIKE') { return { text: `(${tableName}.${field} ${operator} $${currentIndex})`, values: [`%${value}%`], index: currentIndex + 1 }; } if (operator === 'BETWEEN' && Array.isArray(addField) && addField.length === 2) { const startValue = queryParams[addField[0]]; const endValue = queryParams[addField[1]]; return (startValue && endValue) ? { text: `(${tableName}.${field} ${operator} $${currentIndex} AND $${currentIndex + 1})`, values: [startValue, endValue], index: currentIndex + 2 } : null; } if (operator === 'IN' && Array.isArray(addField) && addField.length > 0) { const values = queryParams[addField]; if (Array.isArray(values) && values.length > 0) { const placeholders = values.map((_, index) => `$${currentIndex + index}`).join(', '); return { text: `(${tableName}.${field} ${operator} (${placeholders}))`, values: values, index: currentIndex + values.length }; } return null; } return { text: `(${tableName}.${field} ${operator} $${currentIndex})`, values: [value], index: currentIndex + 1 }; }; |
IN
句を扱う際のポイント
誤った実装例(多次元配列の問題)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
let queryValues = []; if (wheres.length > 0) { wheres.forEach(condition => { if (condition.text) { queryText.push(condition.text); if (condition.value !== undefined) { queryValues.push(condition.value); } if (condition.values !== undefined) { queryValues.push(condition.values); // ここで多次元配列の可能性がある } } }); } |
上記のコードでは、queryValues
に配列をそのまま追加してしまうため、多次元配列になる可能性があります。
修正後の正しい実装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
let queryValues = []; if (wheres.length > 0) { wheres.forEach(condition => { if (condition.text) { queryText.push(condition.text); if (condition.value !== undefined) { queryValues.push(condition.value); } if (Array.isArray(condition.values) && condition.values.length > 0) { queryValues.push(...condition.values); // スプレッド構文で展開し追加 } } }); } |
この修正により、多次元配列になることを防ぎ、期待どおりのフラットな配列が得られます。
まとめ
- Node.jsでSQLクエリを動的に生成する際は、プレースホルダーを活用して安全に実装する。
IN
句を扱う場合、多次元配列が発生しないよう、スプレッド構文を使用する。Array.isArray()
とlength > 0
を組み合わせて適切なデータチェックを行う。- オプショナルチェーン(
?.
)を活用すると、簡潔なコードが書ける。
このような工夫をすることで、安全で柔軟なSQLクエリを生成でき、バグの少ないシステム開発が可能になります。ぜひ、実装の際に参考にしてください。
コメント