カテゴリ: Flask 更新日: 2026/02/10

FlaskでSQLインジェクションを防ぐ方法!初心者でもわかる安全なデータベース操作

FlaskでSQLインジェクションを防ぐ方法!ORMと生SQLの注意点を解説
FlaskでSQLインジェクションを防ぐ方法!ORMと生SQLの注意点を解説

先生と生徒の会話形式で理解しよう

生徒

「Flaskでデータベースにアクセスする方法を調べていたら、『SQLインジェクション』っていう言葉を見つけました。これって何ですか?」

先生

「とても大事なテーマですね。SQLインジェクションとは、悪意のあるユーザーがデータベースを不正に操作するために、SQL文(データベースに送る命令)に細工をする攻撃のことです。」

生徒

「うわ、それって怖いですね。どうすれば防げるんですか?」

先生

「Flaskでは、ORMやプレースホルダという仕組みを使えば安全にできますよ。それでは詳しく見ていきましょう!」

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

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

SQLインジェクションとは、ユーザー入力に悪意のある文字列を混ぜることで、データベースに送るSQL文の意味をねじ曲げ、意図しない操作を実行させる攻撃のことです。Flaskのログインフォームや検索フォームのように、入力内容を使ってデータベース検索をする場面で起きやすく、情報漏えい・不正ログイン・データ改ざんや削除につながる危険があります。

初心者がやりがちなのが、入力をそのまま文字列としてSQLに組み込む方法です。次の例は、一見シンプルですがとても危険です。


username = request.args.get('username')
query = f"SELECT * FROM users WHERE name = '{username}'"

ここでusername' OR '1'='1のような入力をされると、「名前が一致する人だけ」という条件が壊れてしまい、全件が返る可能性があります。つまり、攻撃者が入力欄を利用して、SQL文の一部を書き換えてしまうのがSQLインジェクションの怖さです。

試しにイメージしやすいよう、文字列がどうつながるかだけを見てみましょう(データベースには送らない前提の例です)。


username = "' OR '1'='1"
query = f"SELECT * FROM users WHERE name = '{username}'"
print(query)

このように、入力の中に含まれた記号や条件がSQL文として解釈されると、想定していないデータベース操作が起きてしまいます。

2. ORM(オーアールエム)を使うと安全

2. ORM(オーアールエム)を使うと安全
2. ORM(オーアールエム)を使うと安全

Flaskでは、SQLAlchemyというライブラリを使うことで、ORM(オブジェクト関係マッピング)という仕組みを利用できます。ORMとは、データベースのテーブルや行を、Pythonのクラスやオブジェクトとして扱えるようにする考え方です。

プログラミング未経験者にとって、SQL文を直接書くのは難しく、間違えやすい部分でもあります。ORMを使えば、「データを探す」「1件だけ取り出す」といった操作を、Pythonの命令として直感的に書けるため、SQLの文法を細かく意識しなくて済みます。

さらに重要なのが、ORMは内部で安全なSQLを自動生成してくれる点です。ユーザーの入力値をそのままSQL文に埋め込むことがないため、SQLインジェクションが起きにくくなります。

例えば、ユーザー名を使ってデータを1件取得したい場合、次のように書くだけで安全な検索ができます。


from models import User

user = User.query.filter_by(name=username).first()

このコードでは、「usersテーブルからnameが一致する最初の1件を取得する」という意味になります。SQL文を自分で組み立てていないため、入力内容に記号や不正な文字列が含まれていても、SQLの構造が壊れることはありません。

このように、ORMを使うことは「書きやすさ」と「安全性」を同時に高める方法として、Flaskでのデータベース操作では特におすすめです。

3. 生のSQLを書くときの注意点

3. 生のSQLを書くときの注意点
3. 生のSQLを書くときの注意点

基本はORMが安心ですが、集計や複雑な検索などで「どうしてもSQLを直接書きたい」場面も出てきます。そのときにやってはいけないのが、ユーザーの入力を文字列としてSQL文に足し込む方法です。見た目は簡単でも、条件の一部を書き換えられてしまい、SQLインジェクションの原因になります。

生のSQLを使う場合は、必ずプレースホルダ(パラメータ)を使って値を別で渡しましょう。プレースホルダとは、SQL文の中に:nameのような「入れ物」を用意しておき、実際の値は後から指定する書き方です。これなら入力がそのままSQLとして解釈されにくく、安全なデータベース操作につながります。

例えば、ユーザー名で検索する場合は次のように書きます。


from sqlalchemy import text

query = text("SELECT * FROM users WHERE name = :name")
result = db.session.execute(query, {"name": username})

この書き方だと、SQL文は「検索の形」だけが先に決まり、usernameの中身は別の値として渡されます。そのため、入力に記号や不自然な文字列が混ざっていても、SQL文の構造が壊れにくくなります。

イメージしやすいように、危険な例と安全な例を比べてみましょう。


# 危険:入力をSQL文字列に直接つなげている
query = f"SELECT * FROM users WHERE name = '{username}'"

# 安全:プレースホルダで値を別に渡している
query = text("SELECT * FROM users WHERE name = :name")

生のSQLを書くときは、「文字列連結をしない」「プレースホルダで渡す」をセットで覚えておくと、Flaskでも安心してSQLAlchemyを使った検索ができます。

4. ユーザーの入力は必ず検証する

4. ユーザーの入力は必ず検証する
4. ユーザーの入力は必ず検証する

ORMやプレースホルダを使っていても、ユーザー入力を「そのまま受け入れる」のは避けたいところです。入力チェック(バリデーション)を入れておくと、想定外の値が入って処理が止まったり、ログがエラーだらけになったりするのを防げます。特にFlaskでは、フォーム・URLパラメータ・検索ボックスなど、入力の入口が多いので、早い段階でチェックするのが安心です。

チェックの考え方はシンプルで、「この項目には何が入るはずか?」を決めて、それ以外を弾きます。たとえばユーザー名なら、英数字だけ・長さは20文字まで、といったルールが作りやすいです。数字しか入らないIDに文字が混ざっていないか、空文字のまま送られていないか、極端に長い文字列が来ていないか、という確認だけでも防御になります。

FlaskにはWTFormsのような入力チェック用ライブラリもありますが、まずは「最低限のルール」をコードで入れるだけでも十分役に立ちます。


username = request.args.get('username', '').strip()

# 例:空欄、長すぎ、英数字以外は弾く(シンプルな入力チェック)
if not username:
    return "ユーザー名を入力してください"
if len(username) > 20:
    return "ユーザー名が長すぎます"
if not username.isalnum():
    return "不正な入力です"

このように、入力を受け取った直後にチェックしておくと、後続の処理が安定します。結果として、データベース操作の安全性だけでなく、アプリ全体のトラブルも減らせます。

5. Flaskとデータベースの接続は慎重に

5. Flaskとデータベースの接続は慎重に
5. Flaskとデータベースの接続は慎重に

SQLインジェクション対策として、常に安全な方法でデータベースとやり取りすることが大切です。ORMの使用、プレースホルダの活用、そしてユーザー入力の検証を組み合わせることで、Flaskアプリケーションはより強固なセキュリティを保つことができます。

また、管理者のページや重要なデータを扱う画面では、アクセス制限や認証も組み合わせて、より安全なWebアプリケーションにしていきましょう。

6. エラーメッセージをそのまま表示しない

6. エラーメッセージをそのまま表示しない
6. エラーメッセージをそのまま表示しない

SQLインジェクション対策では、入力値の扱いだけでなく、エラーの出し方にも注意が必要です。データベースエラーの内容をそのまま画面に表示すると、テーブル名やSQL文の構造など、攻撃に役立つ情報を与えてしまうことがあります。

例えば、例外の内容をそのまま返すのは避けましょう。


try:
    user = User.query.filter_by(name=username).first()
except Exception as e:
    return str(e)

代わりに、ユーザーには一般的なメッセージだけを返し、詳細はログに残すようにすると安全です。

7. 最小権限のデータベースユーザーを使う

7. 最小権限のデータベースユーザーを使う
7. 最小権限のデータベースユーザーを使う

もしSQLインジェクションが起きてしまっても、被害を最小限に抑える工夫ができます。その代表が「最小権限」の考え方です。Flaskアプリが使うデータベースユーザーに、必要以上の権限を持たせないようにします。

例えば、読み取りだけの画面なのに、削除(DELETE)や更新(UPDATE)までできる権限があると、攻撃されたときにデータを消される危険が高まります。

アプリ用のユーザーは、必要な操作(SELECT、INSERTなど)だけに絞り、管理者権限は別アカウントに分けると、より安全なデータベース操作につながります。

8. ログを残して不審なアクセスに気づけるようにする

8. ログを残して不審なアクセスに気づけるようにする
8. ログを残して不審なアクセスに気づけるようにする

SQLインジェクション対策は「防ぐ」だけでなく、「気づく」ことも大切です。攻撃は何度も試されることが多いため、アプリ側でログを残しておくと、不審な入力や異常なアクセスに早く気づけます。

例えば、ログインフォームや検索フォームなど、ユーザー入力が多い場所は特にチェック対象になります。極端に長い文字列や、記号が多い入力が続く場合は注意が必要です。

Flaskでは標準のログ機能を使って、入力エラーや例外の発生を記録できます。ORMやプレースホルダで安全にSQLを扱いつつ、ログも組み合わせることで、より安心できるWebアプリケーションに近づきます。

まとめ

まとめ
まとめ

Flaskでデータベースを扱う際に避けて通れないのが、SQLインジェクションという脅威についての理解と、その防ぎ方を知ることでした。今回の記事では、初心者でも迷わず学べるように、SQLインジェクションの危険性と、Flaskで安全にデータベース操作を行うための実践的な方法をていねいに整理しました。まず、SQLインジェクションは悪意のある入力を利用して意図しないSQL文を実行させる攻撃であり、データ漏えい・削除・書き換えなど深刻な被害につながる可能性があります。入力した文字列がそのままSQL文に挿入されてしまうと、攻撃者は自由にデータベースに命令を送れてしまうため、Webアプリケーションの脆弱性として特に注意すべき点です。 しかし、FlaskではORM(SQLAlchemy)を活用することで、このリスクを大幅に減らすことができます。ORMはSQL文を直接書かずにPythonオブジェクトとしてデータベースを扱えるため、SQLインジェクションの攻撃経路がほぼ遮断される強力な方法です。また、どうしてもSQL文を書きたい場合でも、プレースホルダを活用し、値とSQL文を分離して実行することで、攻撃者の入力がそのままSQL文として解釈されるのを防げます。この手法は初心者でも取り組みやすく、Flaskアプリの安全性を高めるうえで欠かせません。 さらに、ユーザー入力を必ず検証することも大切です。数字のみを受け付ける場所に文字が入っていないか、極端に長い入力がないか、特殊文字が混じっていないかなど、入力チェックを行うだけでも安全性は大きく向上します。FlaskにはWTFormsのような便利なライブラリもありますが、まずはシンプルなバリデーションでも十分効果があります。 安全なアプリを作るには、ORM・プレースホルダ・入力チェックを組み合わせることが重要であり、これらを習慣にすることで、安心してデータベースを扱えるFlaskアプリが構築できます。ここでは、記事の流れを振り返りつつ、実際に応用できるサンプルコードをまとめておきます。

安全なデータベース操作のサンプルコード


# ORMを使った安全な検索例
from models import User

def find_user(username):
    user = User.query.filter_by(name=username).first()
    return user

# プレースホルダを使った安全なSQL実行例
from sqlalchemy import text
from app import db

def find_user_safe(username):
    query = text("SELECT * FROM users WHERE name = :name")
    result = db.session.execute(query, {"name": username})
    return result.first()

# 入力チェックの例
def validate_username(username):
    if not username.isalnum():
        return "不正な入力です"
    return "入力OK"

上記のように、ORMを使う方法、プレースホルダを使う方法、そして入力チェックを組み合わせることで、SQLインジェクションの脅威を最小限に抑えることができます。Flaskは軽量なフレームワークでありながら、SQLAlchemyのような強力なツールと組み合わせることで、安全で柔軟なデータベース操作が可能です。これらの方法を活用することで、ユーザー情報の検索、ログイン処理、データ登録、絞り込み検索などを安全に実装でき、自信を持ってFlaskアプリの開発を進められるようになります。 また、実際のアプリケーションでは、セキュリティチェックに加えてアクセス制限や認証を組み合わせることでさらなる安全性を確保できます。管理画面や重要なデータを扱うページでは特に慎重な設計が求められ、SQLインジェクション以外の脅威からも守るための意識が大切です。今回学んだ内容をしっかり理解しておくことで、これからのFlask開発がより安全で安定したものへと成長していくことでしょう。

先生と生徒の振り返り会話

生徒

「SQLインジェクションって名前だけで難しいと思っていましたけど、実例を見たら怖さがよくわかりました。でも対策も意外とシンプルなんですね!」

先生

「そうなんです。ORMやプレースホルダを使うだけで安全性が大きく高まりますし、Flaskの仕組みをうまく利用すれば初心者でも安全なアプリを作れますよ。」

生徒

「入力チェックをするだけでも防げる部分があるのが意外でした。次からは必ずチェックを入れるようにします!」

先生

「その意識はとても大切ですね。安全なアプリを作るためには、毎回ていねいにデータを扱うことが重要です。今回の内容がしっかり理解できていれば、より高度なデータベース操作にも挑戦できますよ。」

生徒

「もっとFlaskでデータベースを使ったアプリを作ってみたくなりました!ありがとうございました!」

この記事を読んだ人からの質問

この記事を読んだ人からの質問
この記事を読んだ人からの質問

プログラミング初心者からのよくある疑問/質問を解決します

SQLインジェクションとは何ですか?初心者でも分かるように説明してほしいです。

SQLインジェクションとは、ユーザーが入力した内容に悪意のある文字列を混ぜて、データベースに不正な命令を実行させる攻撃のことです。Flaskでデータベース操作を行う際には必ず意識すべき危険な攻撃方法で、対策しないとデータの削除や書き換えなど重大な被害につながります。
カテゴリの一覧へ
新着記事
New1
Flask
認証と認可の違いを整理しよう!Flaskで押さえるべき基礎概念
New2
Flask
Flaskで非同期フォーム送信(Ajax POST)を実装する方法を解説!初心者でもわかるステップ解説
New3
Python
Pythonで定数を定義する方法!変更されない変数の書き方と命名ルールを初心者向けに解説
New4
Python
PythonでMySQLに接続する方法!pymysqlの基本的な使い方
人気記事
No.1
Java&Spring記事人気No1
Python
Pythonとは何か?初心者向けにできること・特徴・インストール手順までやさしく解説
No.2
Java&Spring記事人気No2
Flask
Flaskでデータベースを使う基本!SQLAlchemyの導入方法をやさしく解説
No.3
Java&Spring記事人気No3
Python
Pythonでリストの要素を検索・取得する方法!index()やin演算子の活用法
No.4
Java&Spring記事人気No4
Python
Pythonのインストール方法まとめ!Windows・Mac・Linux別にステップ解説
No.5
Java&Spring記事人気No5
Python
Pythonプログラムの書き方を基礎から学ぼう!初心者が覚えるべき文法とは?
No.6
Java&Spring記事人気No6
Python
Pythonで仮想環境(venv)を作る方法!初心者向けに環境構築をステップ解説
No.7
Java&Spring記事人気No7
Flask
Flaskアプリの環境変数をクラウドで安全に設定する方法!初心者のための完全ガイド
No.8
Java&Spring記事人気No8
Python
PythonでHello Worldを表示するには?初心者向けに最初の1行を実行してみよう