手を振るまもるくんゆるふわサイバーセキュリティ
考え中のまもるくん

SQLインジェクションを防ぐPython実装|なぜ文字列連結が危ないのか

2026-09-14実践

#SQLインジェクション#防御#パラメータ化#Python#実践

Webアプリの脆弱性の代表格 SQLインジェクション。攻撃手法を覚えるより、**「なぜ起きるか」と「どう根本的に防ぐか」**を理解するのがエンジニアの仕事です。この記事ではPythonのsqlite3で、危険なコードと安全なコードを並べて防御を体得します。Webの脆弱性の実装編です。

なぜ起きるのか:入力がSQLの一部になる

原因はただ一つ、ユーザー入力を文字列連結でSQLに混ぜること。入力が「データ」ではなく「命令」として解釈されてしまうのが問題の本質です。

準備

標準ライブラリのsqlite3だけ。

① 危ない書き方(文字列連結)

import sqlite3

db = sqlite3.connect(":memory:")
db.execute("CREATE TABLE users(name TEXT, secret TEXT)")
db.execute("INSERT INTO users VALUES ('alice', 'topsecret')")

def login_unsafe(name):
    # ❌ 絶対にやってはいけない:入力を直接埋め込む
    query = f"SELECT secret FROM users WHERE name = '{name}'"
    return db.execute(query).fetchall()

# 普通の入力なら動くが…
print(login_unsafe("alice"))
# 入力が「命令」になってしまう例(' OR '1'='1)
print(login_unsafe("x' OR '1'='1"))   # 全員のsecretが漏れる!

x' OR '1'='1 という入力で、WHERE条件が常に真になり全レコードが漏洩します。入力がSQLの構造そのものを書き換えたのが原因です。

② 安全な書き方(パラメータ化クエリ)

入力を?のプレースホルダで渡すと、DBが入力を必ず「データ」として扱い、命令として解釈しません。

def login_safe(name):
    # ✅ 入力はパラメータとして渡す(連結しない)
    return db.execute("SELECT secret FROM users WHERE name = ?", (name,)).fetchall()

print(login_safe("alice"))                # 正常
print(login_safe("x' OR '1'='1"))         # → [] 何も漏れない

同じ悪意ある入力でも、パラメータ化すれば [](該当なし)。入力は単なる文字列として扱われ、攻撃が成立しません。

🌱

覚えることは1つだけ

「ユーザー入力をSQL文字列に連結しない。必ずプレースホルダで渡す」——これだけでSQLインジェクションはほぼ根絶できます。ORMを使う場合も、生SQLを書くときは同じ原則です。

⚠️

多層防御も忘れずに

パラメータ化が最重要ですが、加えて「入力値の検証」「DBユーザーの権限最小化」「エラーメッセージに内部情報を出さない」を重ねると、より堅牢になります。1つの対策に頼らないのがセキュリティの基本です。

まとめ

  • SQLインジェクションは「入力を文字列連結でSQLに混ぜる」ことが原因
  • 入力がデータでなく命令として解釈され、情報漏洩や改ざんに繋がる
  • 対策はパラメータ化クエリ(?で渡す)。入力は必ずデータ扱いになる
  • 入力検証・権限最小化・エラー秘匿の多層防御を重ねる

もう少し詳しく(背景と理論)

SQLインジェクションは、ユーザー入力を文字列連結でSQL文に埋め込むことで、攻撃者が任意のSQLを注入できてしまう脆弱性です(CWE-89)。OWASP Top 10 で長年上位を占める代表的なインジェクション欠陥です1。根本対策はプレースホルダを使ったパラメータ化クエリ(プリペアドステートメント)——データとコードを分離し、入力が「値」としてしか解釈されないようにします2。これはエスケープ処理より確実で、多くのORMもこの仕組みの上に立っています。加えて、DBアカウントの権限は必要最小限に絞る最小権限の原則を併用し、万一の被害範囲を限定します3

次の一歩 🌸

他のWeb脆弱性はWebの脆弱性、出力側の対策はXSSとエスケープ、通信の保護はHTTPSのしくみへどうぞ。

Footnotes

  1. OWASP Top 10 の Injection(A03:2021)。SQLi は CWE-89 に分類される古典的かつ影響の大きい脆弱性。

  2. パラメータ化クエリは SQL の構文(コード)と入力(データ)を分離する。入力は常に値として扱われ、構文を書き換えられない。

  3. アプリ用DBユーザーには必要な操作のみ許可する。侵入されても DROP や他テーブル参照を防ぎ、被害を局所化できる。

🔥 この分野の最新トレンドをチェック →

あわせて読みたい