36
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「’ or ‘1’=‘1」これを見てピンと来ない人、危険ですよ。

Last updated at Posted at 2025-12-02

(本記事は理解促進のためのフィクションであり、実在のシステム・ログ・顧客環境とは一切関係ありません。)

 

ある日、会社のSlackでこんな会話を目にしました。

Frame 5.png

投稿したのは、機械学習エンジニア出身で、最近アプリ側も触るようになった後輩くん。
普段は、「モデルの精度が〜」とか「学習曲線が〜」と言ってるタイプの彼が、珍しくログを貼ってきた。

最初は「ふざけて変な文字列を入れたユーザーでもいたのかな?」
くらいに思っていたのですが----

次の瞬間、背筋がすっと冷えました。

これは、SQLインジェクション攻撃の典型的なパターンだ。

「え、マジですか?」

一旦状況を整理するために、このログが示すものを説明しました。

「これね、全然笑えないよ。
ログに出てる ' or '1'='1 って、"条件を常に真にする"ための魔法の呪文みたいなものなんだよ」

後輩くんも状況がわかったようで、「これ、結構やばいですかね?」と焦り気味。

もちろんやばい。
でも本当に怖いのは、アプリの実装がこの攻撃を想定していないかもしれないことだ。

Slackのチャンネルが一気にざわつく

別のメンバーも反応し始めます。

「これ、検証ログだよね...?」
「対象APIってどのエンドポイント?」
「そもそもPrepared Statement使ってるっけ?」

普段は静かなチャンネルが、急に"何か起きてる感"で満ちていく。

後輩くんはさらに混乱して、

「え、SQLインジェクションってそんなに危険なんですか?」

と聞いてきました。

SQLインジェクションとは?

まずは定義から。

ユーザーの入力欄に、データベース操作の"命令"を紛れ込ませて、アプリに誤って実行させる攻撃のことです。

Webアプリはどこかで必ずSQLを使ってデータベースに問い合わせますよね。
そのSQL文を文字列連結して作っていると、
攻撃者にとっては"書き換え放題の裏口"になります。

' or '1'='1 がその代表例です。

▼何が起きるの?

ログイン画面で例えると、

SELECT * FROM users WHERE name = '$name';

こういう実装をしている場合、
攻撃者は $name に次のように入力します。

' OR '1'='1

すると、SQL文はこうなります:

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

'1'='1'は常に真。

つまり、

文字列連結でSQLを組み立てていると、' OR '1'='1 のような入力によりWHERE句が常に真となり、パスワード検証や返却レコードの扱いに不備がある場合は認証を突破される恐れがあります。

これがSQLインジェクションの最小構成です。
"小学生でもできる攻撃"と呼ばれることすらあります。

じゃあ、実行されるとどうなる?

1. 個人情報の漏えい

SQLインジェクションが成立すると、攻撃者は次のようなSQLも実行できます。

SELECT * FROM users;

つまり、

  • 氏名
  • 住所
  • メールアドレス
  • パスワード(ひどいと平文)
  • クレジットカード情報
    など、全部盗める状況になります。

本当にあった過去の個人情報漏えい事件😨
SQLインジェクション 個人情報漏洩」といったキーワードで検索すると、本当にあった過去の事件を多数確認することができます。

2. データ改ざん・削除(地獄です)

攻撃者の目的が破壊なら、もっとひどいです。

DELETE FROM users;
DROP TABLE orders;
UPDATE accounts SET balance=0;

これすら実行できます。

3. 管理者権限奪取 → サイト乗っ取り

もし管理者アカウント情報まで奪われると、
プラットフォームごと支配されます。

  • サイトにマルウェアを仕込む
  • 偽のページに書き換える
  • 全ユーザーをフィッシングに誘導する

ここまで来ると、一般企業ではほぼ対応不能です。

じゃあどうすれば防げるの?

ここが重要なポイント💡

実はSQLインジェクションは、
基本さえ守ればほぼ防げる攻撃でもあります。

1. プリペアドステートメント(Prepared Statement)を使う【最重要】

すべての対策の中で最強で必須。
プリペアドステートメントを使うと、
SQL文とデータ(ユーザー入力)が完全に分離されるので、

「命令として実行されない」

という状態が作れます。

❌️ 悪い例(文字列連結)

cur.execute(f"SELECT * FROM users WHERE name = '{name}'")

✅️ 良い例(パラメータ化クエリ、プリペアドステートメント)

cur.execute("SELECT * FROM users WHERE name = ?", (name,))

これだけで ' or '1'='1 の攻撃は防げます!

2. 入力のバリデーション・サニタイズ

  • 数字なら数字だけ
  • 文字列の長さ制限
  • 危険な文字をエスケープ

これは補助的な対策ですが、確実に効果があります。

3. ORMやフレームワークを使う

ORMは内部で自動的にプリペアドステートメントを使うため、
生SQLを書かない限り安全になりやすい。

4. エラーメッセージに内部情報を出さない

攻撃者にヒントを与えるだけです。
本番では一般的なメッセージだけ返しましょう。

5. DB権限の最小化

  • 読み込みだけなら「読み込み専用ユーザー」
  • 管理者権限は極力使わない

まとめ:SQLインジェクションは「今すぐ知るべき基本」

Slackの"変なログ"から始まった今回の話。

後輩くんと同じように、
「知らない=危険に気付けない」 という状況は多くの現場で起こり得ます。

SQLインジェクションは怖い攻撃ですが、
逆に言えば、プリペアドステートメントを使うだけでも大部分を防げます。

今日のポイントはこれ。

SQLインジェクション対策の最重要ポイント
「入力されたものは、常に攻撃を意識して扱う」
「SQLは絶対に文字列連結しない」
「プリペアドステートメントを使う」


補足(免責)

本記事のエピソードは、理解を深めるために構成したフィクションです。
登場する人物・会話・ログなどはすべて筆者による創作であり、実在の社員・組織・システムを示すものではありません。

36
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?