1. 普通の言葉ならどちらも1件
  2. 攻撃文字列。つなぐ書き方だと全件が漏れる
  3. 無い商品名ならどちらも0件
コース一覧
Node.js入門
SQLインジェクション

Node.js入門

Node.jsの実行モデル、npm、Expressによるルーティング、REST API設計、データベース接続、トランザクションを使った購入処理、トークン認証まで、バックエンド開発の基礎を、毎レッスン実際にコードを書き、フリマアプリのAPIを自分の手で作りながら学びます。

1
Node.jsとは
01. Node.jsとは15分
02. スクリプトを実行する15分
03. npmとは15分
04. package.json15分
05. npmスクリプト15分
06. つくる:プロジェクト始動20分
07. 第1章クイズ10分
2
モジュールと非同期の復習
01. import/export15分
02. ファイルを読み書きする15分
03. async/await復習15分
04. JSONの取り回し15分
05. つくる:データ層20分
06. 第2章クイズ10分
3
はじめてのサーバー
01. サーバーとリクエスト15分
02. Expressを導入する15分
03. ルーティング15分
04. JSONを返す15分
05. 開発の回し方15分
06. つくる:サーバー始動20分
07. 第3章クイズ10分
4
REST APIのきほん
01. RESTの考え方15分
02. 一覧を返す15分
03. 1件を返す15分
04. 登録を受ける15分
05. 更新と削除15分
06. ステータスコード15分
07. つくる:商品CRUD完成20分
08. 第4章クイズ10分
5
リクエスト処理と検証
01. クエリパラメータ15分
02. 並び替えとページング15分
03. 入力検証15分
04. ミドルウェア15分
05. エラーハンドリング15分
06. つくる:検索API完成20分
07. 第5章クイズ10分
6
データベース接続
01. DBにつなぐ15分
02. 一覧・詳細をDB化15分
03. 出品をDB化15分
04. SQLインジェクション20分
05. 更新・削除をDB化15分
06. 購入トランザクション20分
07. つくる:DB版fleama20分
08. 第6章クイズ10分
7
認証のきほん
01. 認証と認可15分
02. パスワードハッシュ15分
03. ログインとトークン15分
04. 保護ルート15分
05. 本人のものだけ15分
06. つくる:認証完備20分
07. 第7章クイズ10分
8
総合制作
01. fleama API完成20分
02. Reactと接続する20分
03. サーバーで常駐させる20分
04. 自由拡張20分
05. 完成と次のステップ15分

SQLインジェクション

なぜ ? を使うのか

前のレッスンで、値を ? に渡しました。文字列をつないでも同じ SQL になりそうです。

JavaScript

db.prepare("SELECT * FROM items WHERE name = '" + keyword + "'").all();

普通の検索なら動きます。ですがこの書き方は、fleama の商品を全部盗み出せる穴になります。

検索欄に SQL を書かれる

受講者が次の文字列を検索欄に入れたとします。

プレーンテキスト

' OR '1'='1

つなぐと、こういう SQL ができあがります。

SQL クエリ

SELECT * FROM items WHERE name = '' OR '1'='1'

'1'='1' はいつでも成り立ちます。つまり条件が消えて全件が返ります。非公開の商品も、下書きも、すべてです。

閉じるはずの ' が、入力に含まれていたために早く閉じてしまった。ここが原因です。入力がデータではなく、SQL の一部として読まれたわけです。

もっと危ないこともできる

読まれるだけでは済みません。

プレーンテキスト

'; DELETE FROM items; --

これで商品を全部消せます。-- から後ろは注釈として無視されるので、後ろに何が続いていても関係ありません。

この攻撃を SQL インジェクションと呼びます。日本語では「SQL の注入」です。

プレースホルダが防ぐ理由

JavaScript

db.prepare("SELECT * FROM items WHERE name = ?").all(keyword);

こう書くと、' OR '1'='1 はそういう名前の商品を探すだけになります。0 件です。

違いは、SQL の形を先に決めてしまう点にあります。? の場所に入るものは、どんな文字が来ても値としてしか扱われません。SQL の構造をあとから書き換えることはできません。

文字列を組み立ててから解釈させるのか、形を決めてから値を差し込むのか。 この順番が安全を分けます。

逃がす処理を自分で書かない

「危ない文字を消せばよい」と考えたくなりますが、やめてください。抜け道が多く、専門家でも塞ぎきれません。

外から来た値を SQL につながない。 これだけを守れば、この攻撃は成立しません。

手を動かす

演習では、まず攻撃が成立することを自分の目で確かめ、そのうえで直します。危険を知らないまま防ぐことはできません。

要件

  1. unsafe は WHERE name = ' に値をつないで組み立てた SQL で数える
  2. safe は WHERE name = ? のプレースホルダで数える
  3. どちらも件数を数値で返す

入出力例

search("レザースニーカー") → {"safe":1,"unsafe":1} search("' OR '1'='1") → {"safe":0,"unsafe":3} search("帽子") → {"safe":0,"unsafe":0}

ヒント

初期コードは両方ともプレースホルダなので、差が出ません。`unsafe` のほうを書き換えます

つなぐ書き方は `"... WHERE name = '" + keyword + "'"` です。`.get()` に引数は渡しません

`safe` のほうは触りません。2 つを並べると、同じ入力で結果が変わることが見えます

生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/08/10

関連レッスン

  • 更新・削除をDB化

    編集と取下げをDB化し、変更系を移行できるようになります。

  • 購入トランザクション

    売切れ化と購入記録を不可分にし、複数の更新を一括で処理できるようになります。

  • つくる:DB版fleama

    全APIをDBで動かし、データ層を丸ごと移行できるようになります。

  • 第6章クイズ

    データベース接続とトランザクションの理解を4択で確認します。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • SQLデータベースを操作するための共通言語
  • プレースホルダSQL の `?` 部分にあとから値を入れる仕組み
  • 処理計算や代入を表す長方形
main.js
学習モード
エディタを読み込んでいます

メモ

SQLインジェクション

⌘S で保存