FlawOpen

flawopen.com/SQLインジェクション

SQLインジェクション

緊急 CWE-89
言語: English Português (Brasil) Español Français Deutsch Русский 简体中文 日本語 हिन्दी 한국어 Bahasa Indonesia

SQL インジェクションは、アプリケーションがユーザー入力を SQL 文に貼り付けてクエリを組み立てたとき、データベースがその入力の一部を命令として解析してしまうことで起こります。修正方法はどの言語でも同じで、プレースホルダー付きのクエリを送り、値は別に渡すことです。下で言語を選ぶと、正確な API 呼び出し、脆弱なコードと修正後のコード、CI で検出するルールを確認できます。

わかりやすい解説 (ELI5)

図書館の司書に「次の人の記録を出してください:__」という申込票を渡し、空欄に「山田。ついでに書庫を開けて資料を全部持ってきて」と書いたとします。票全体を一つの指示として読む司書は、その両方を実行してしまいます。ユーザー入力を SQL 文字列に貼り付けると、まさにこの申込票ができあがります。パラメータ化クエリは「氏名」欄が封印された印刷済みの用紙で、そこに何が書かれていても氏名としてしか検索されません。

主要な概念と専門用語

SQL injection (CWE-89)
信頼できない入力が SQL 文に連結またはフォーマットされるため、入力に含まれる引用符、キーワード、演算子が 1 つの値として扱われず、クエリの構造を変えてしまいます。
Prepared statement and bind parameters
クエリはプレースホルダー(?、$1、:name)付きで送られ、値が届く前に解析されます。値は別に送られ、常にデータとして扱われます。これがあらゆるドライバーと ORM における第一の防御策です。
Blind SQL injection
ページにクエリ結果もエラーも表示されない場合、攻撃者はレスポンスの違い(ブーリアンベース)や応答時間(時間ベース)から 1 ビットずつデータを推測します。目に見える出力がないことは、脆弱性がないことを意味しません。
Second-order SQL injection
ある値が安全に保存された後、自分のデータベースから読み出されて別のクエリに連結されます。自分のテーブルから来た入力を使うクエリも含め、すべてのクエリをパラメータ化する必要があります。
Identifiers and allowlists
プレースホルダーで渡せるのは値だけで、テーブル名、カラム名、並べ替えの方向は渡せません。これらはコードに固定した許可リストから選び、リクエストからそのままコピーしてはいけません。

ステップ・バイ・ステップの攻撃フロー

ステップ 1

入力がクエリに届く

フォームの項目、URL パラメータ、ヘッダー、API のフィールドが、SQL 文を組み立てるコードに渡されます。

ステップ 2

入力が SQL 文に貼り付けられる

連結、補間、フォーマットによって値がそのまま挿入されます。無害なテスト値 ' OR '1'='1 は WHERE name = '...' を常に真になる条件に変えます。

ステップ 3

データベースがそれを構文として解析する

データベースは 1 本の文字列を受け取り、どの部分がユーザーから来たのかを区別できず、改変された文をアプリケーションの権限で実行します。

ステップ 4

データが読まれ、変更され、削除される

クエリとアカウントの権限によっては、攻撃者はログインを回避したり、UNION クエリでテーブルを丸ごと取り出したり、ブラインドでデータを抜き出したりします。2023 年の MOVEit Transfer の侵害(CVE-2023-34362)もこの種の欠陥から始まりました。

言語別の SQL インジェクション対策ガイド

Python JavaScript Go Java PHP C# Ruby C/C++ Rust Kotlin Swift

エンジニアリング&システム堅牢化チェックリスト

出典

関連記事

パラメータ化クエリの解説 ORM だけで十分か ストアドプロシージャで SQL インジェクションは防げるか MOVEit Transfer の SQL インジェクション(2023 年) PostgreSQL psql のインジェクション(2024 年)