JavaScriptの変数をSQL文に入れる方法とSQLインジェクションの回避

SQL文の中にJavaScriptの変数を入れたい場合、何も考えずにSQLと変数を連結させたり、テンプレートリテラルSQL文を作成すると、SQLインジェクションのリスクが高くなります。
そこで今回は、JavaScript変数プレースホルダーを上手に活用して、SQLインジェクションのリスクが少ないセキュアなSQL文を作成する方法をご紹介します!

SQLインジェクションとは

この手の話は定番中の定番なので、既にご存知の方は読み飛ばしちゃってください。

SQLインジェクションとは、アプリケーションのセキュリティ上の不備を意図的に利用し、アプリケーションが想定しないSQL文を実行させることにより、データベースシステムを不正に操作する攻撃方法のことです。

例えば、以下のようなコードがあったとします。

var name = req.body.name;
var sql = "SELECT * FROM users WHERE name = '" + name + "'";
connection.query(sql, function (error, results) {
  // 省略
});

上記は悪い例ですので、このようなコードは絶対に書かないでください。

このコードでは、name変数にユーザーが入力した値がそのままSQL文に埋め込まれています。
もしnameが以下のような値を入力したらどうなるでしょうか?

name = "' OR 1 = 1 --"

この場合、SQL文は以下のようになります。

SELECT * FROM users WHERE name = '' OR 1 = 1 --'

ここで、はコメント記号であり、それ以降の文字列は無視されます。
つまり、このSQL文は「nameが空文字かどうか、または1が1かどうか」という条件でusersテーブルから全てのレコードを取得することになります。
これは明らかにアプリケーションが想定していない動作です。

さらに悪意のあるユーザーは、データベースの内容を盗み見たり、削除したり、改ざんしたりすることも可能です。

著:伊藤 康太
¥3,278 (2023/04/10 16:56時点 | Amazon調べ)
\楽天ポイント5倍セール!/
楽天市場

プレースホルダーを使ってSQLインジェクションを回避

JavaScriptSQL文を書く際に使用するプレースホルダーとは、SQL文の中に埋め込む変数のようなものです。
プレースホルダーを使うと、SQLインジェクションなどの攻撃を防ぐことができます。

プレースホルダーの書き方

プレースホルダーの書き方は、使用するライブラリやデータベースによって異なりますが、一般的には?$1などの記号を使います。
例えば、以下のようなSQL文があります。

SELECT * FROM users WHERE name = '山田';

このSQL文では、nameの値が固定されていますが、プレースホルダーを使うと以下のように書けます。

SELECT * FROM users WHERE name = ?;

または

SELECT * FROM users WHERE name = $1;

この場合、?$1に対応する値を別途指定する必要があります。
JavaScriptでは、以下のようにqueryメソッド第2引数に配列で渡すことができます。

connection.query('SELECT * FROM users WHERE name = ?', ['山田'], function (error, results) {
  // 結果で何かをする
});

プレースホルダーを使ったSQL文

JavaScriptSQL文の中に変数を入れたい場合は、変数の値を""で囲む必要があります。
例えば、以下のようなコードです。

var name = "sample";
var sql = "INSERT INTO users VALUES(2,'" + name + "')";

また、mysqlモジュールを使っている場合は、プレースホルダー?)を使って変数を埋め込むこともできます。
例えば、以下のようなコードです。

var name = "sample";
var sql = "INSERT INTO users VALUES(2,?)";
connection.query(sql, [name], function (error, results) {
  // 省略
});

どちらの方法もSQLインジェクションのリスクを減らすことができます。

著:ミック
¥2,696 (2023/04/10 16:56時点 | Amazon調べ)
\楽天ポイント5倍セール!/
楽天市場

テンプレートリテラルを使ったSQL文

テンプレートリテラルの基礎

テンプレートリテラルとは、文字列をグレイヴ・アクセントで囲み、変数ドル記号と波括弧でくくることで、文字列に変数の値を埋め込むことができる機能です。
テンプレートリテラルの書き方は、以下のようになります。

  • 文字列をグレイヴ・アクセント(`)で囲む
  • 変数や式を埋め込む場合は、ドル記号($)と波括弧({})でくくります。
  • 改行やタブなどの空白文字はそのまま反映されます。

例えば、以下のようなコードがあります。

var name = "山田";
var age = 20;
var message = `こんにちは、${name}さん!
あなたは${age}歳です。`;

このコードでは、message変数には以下のような文字列が代入されます。

こんにちは、山田さん!
あなたは20歳です。

テンプレートリテラルとは、文字列を定義するときに変数を使用したり、ソース上の改行をそのまま取り込めるというものです。
SQL文の書き方にも便利ですが、注意点もあります。

SQL文で使うと危険!

上記の通り、テンプレートリテラルは大変便利に機能ですが、こちらもやはりそのままSQLの中にJavaScriptの変数を書くのは危険です。

例えば、以下のようにテンプレートリテラルSQL文を作成します。

let name = "山田";
let age = 20;
let sql = `SELECT * FROM users WHERE name = '${name}' AND age = ${age}`;

この場合、変数nameageの値がSQL文に埋め込まれます。
しかし、この方法はSQLインジェクションという攻撃手法に対して脆弱です。

攻撃を防ぐためにも、やはりプレースホルダーを使ってSQL文を作成する必要があります。
例えば、以下のようにテンプレートリテラルプレースホルダーSQL文を作成することができます。

let name = "山田";
let age = 20;
let sql = "SELECT * FROM users WHERE name = ? AND age = ?";
// 変数の値をバインドしてからSQL文を実行する

この場合、変数nameに不正な値が入力されても、その値は文字列リテラルとして扱われるため、想定外の命令は実行されません。

以上がテンプレートリテラルを使ってSQL文の書き方について詳しく教える内容です。

\楽天ポイント5倍セール!/
楽天市場


Amazonベストセラー

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA