FlawOpen

flawopen.com/リファレンス/FastAPI SQLインジェクション

FastAPIはデフォルトでSQLインジェクションを防ぎますか?

Python・APIガイド
要点

Pydanticは値が宣言された入力型に合うかを確認しますが、SQLを書き換えたり、Python文字列をデータベースパラメータに変換したりはしません。検証済みの name: str も、呼び出し元が制御するテキストです。検証は小包の宛名ラベルを確かめる作業、バインドは値をSQLの指示書から分離して封をする作業だと考えてください。SQLテンプレートを固定し、値はSQLAlchemy経由で別に渡します。

FastAPIで危険な書き方と安全な書き方

危険:補間でSQL文字列が変わる
# A string type check does not make input safe inside SQL syntax
@app.get("/users")
def get_users(name: str, db: Session = Depends(get_db)):
    query = text(f"SELECT * FROM users WHERE name = '{name}'")
    return db.execute(query).fetchall()
安全:SQLAlchemyが値を別にバインド
# :name is a bind parameter; the value is passed separately
@app.get("/users")
def get_users(name: str, db: Session = Depends(get_db)):
    query = text("SELECT * FROM users WHERE name = :name")
    return db.execute(query, {"name": name}).fetchall()

パラメータバインドで防げないもの

バインドパラメータで表せるのはデータ値であり、テーブル名、列名、SQL演算子、並び順ではありません。リクエストから並び替え項目を選ばせる場合は、選択肢を固定したSQLAlchemy列式の許可リストに対応付けます。生のリクエスト文字列をSQLに連結してはいけません。パラメータ化は認可の代わりにもなりません。読み取り可能な行を制限し、データベースアカウントにはエンドポイントに必要な権限だけを与えます。

防止チェックリスト

リファレンス

関連項目 SQL インジェクション(CWE-89)の仕組みと各言語での防ぎ方 — flawopen.com GORM Raw SQL:GoでSQLインジェクションを防ぐ 引用符のエスケープだけでSQL Injectionを防げる? ORM を使えば SQL インジェクションを防げるか Knex.jsはSQL Injectionを防げますか? MyBatisの${}と#{}:SQL Injectionを防ぐ MySQLiとPDO:安全なPrepared Statement