
コンピューティングにおいて、SQLインジェクションは、データ駆動型アプリケーションを攻撃するために使用されるコードインジェクション技術であり、悪意のあるSQLステートメントがエントリフィールドに挿入されて実行されます(たとえば、データベースの内容を攻撃者にダンプするため)。[ 1 ] [ 2 ] SQLインジェクションは、アプリケーションソフトウェアのセキュリティ脆弱性を悪用する必要があります。たとえば、ユーザー入力がSQLステートメントに埋め込まれた文字列リテラルのエスケープ文字に対して正しくフィルタリングされていない場合、またはユーザー入力が厳密に型付けされておらず、予期せず実行される場合などです。SQLインジェクションは主にWebサイトの攻撃ベクトルとして知られていますが、あらゆる種類のSQLデータベースを攻撃するために使用できます。
SQLインジェクション攻撃により、攻撃者は身元を偽装したり、既存のデータを改ざんしたり、取引の無効化や残高の変更などの否認問題を引き起こしたり、システム上のすべてのデータを完全に開示したり、データを破壊したり、その他の方法でデータを利用できなくしたり、データベースサーバーの管理者になったりすることが可能になります。ドキュメント指向のNoSQLデータベースも、このセキュリティ脆弱性の影響を受ける可能性があります。[ 3 ]
SQLインジェクションは、機密データを侵害する可能性があるため、広く認識されているセキュリティリスクです。Open Web Application Security Project (OWASP) は、検証されていないユーザー入力を使用してアプリケーションがデータベースクエリを構築する際に発生する脆弱性として説明しています。この欠陥を悪用すると、攻撃者は意図しないデータベースコマンドを実行し、データにアクセス、変更、または削除する可能性があります。OWASPは、プリペアドステートメント、ストアドプロシージャ、入力検証など、ユーザー入力が実行可能なSQLコードとして誤って解釈されるのを防ぐためのいくつかの緩和策を概説しています。[ 4 ]
SQLインジェクションに関する議論は1990年代後半に始まり、1998年のPhrack Magazineの記事でも取り上げられました。[ 5 ] SQLインジェクションは、 Open Web Application Security Project (OWASP)によって2007年と2010年のWebアプリケーションの脆弱性トップ10にランクインしました。[ 6 ] 2013年には、SQLインジェクションはOWASPトップ10で最も深刻なWebアプリケーションの脆弱性として挙げられました。[ 7 ]
2017年、OWASP Top 10 Application Security RisksはSQLインジェクションをより広範な「インジェクション」カテゴリに分類し、3番目に重大なセキュリティ脅威としてランク付けしました。このカテゴリには、SQL、NoSQL、OSコマンド、LDAPインジェクションなど、さまざまな種類のインジェクション攻撃が含まれます。これらの脆弱性は、アプリケーションがコマンドまたはクエリの一部として信頼できないデータを処理する際に発生し、攻撃者が意図しないアクションを実行したり、データへの不正アクセスを取得したりする可能性があります。[ 8 ]
2021 年までに、インジェクションは依然として広範囲にわたる問題であり、分析されたアプリケーションの 94% で検出され、報告された発生率は最大 19% に達しました。その年のOWASP Top 10では、オブジェクトリレーショナルマッピング(ORM) システム、式言語(EL)、オブジェクトグラフナビゲーションライブラリ (OGNL)を標的とした攻撃を含むように、インジェクション脆弱性の定義がさらに拡大されました。これらのリスクに対処するために、OWASP は、セキュアなAPI の使用、パラメータ化されたクエリ、入力検証、クエリの一部として悪意のあるデータが実行されるのを防ぐための特殊文字のエスケープなどの戦略を推奨しています。[ 9 ] [ 10 ]
SQLインジェクションは、攻撃者が提供したデータがSQLコードになることで発生する一般的なセキュリティ脆弱性です。これは、プログラマが文字列補間またはSQLコマンドとユーザー提供データを連結することによってSQLクエリを組み立てるときに発生します。したがって、インジェクションは、SQLステートメントがSQLステートメントで使用されるデータと、SQLステートメントの実行方法を制御するコマンドの両方で構成されているという事実に依存しています。たとえば、SQLステートメントでは、文字列「」はデータであり、フラグメントはコマンドの例です(この例では値もデータです)。[ 11 ]select*frompersonwherename='susan'andage=2susanandage=22
SQLインジェクションは、細工されたユーザー入力が受信プログラムによって処理される際に、入力がデータコンテキストからコマンドコンテキストに移行してしまうことで発生します。これにより、攻撃者は実行されるSQL文の構造を改変することが可能になります。
susan簡単な例として、上記のステートメントのデータ「 」がユーザー入力によって提供されたと想像してください。ユーザーがsusanWebフォームのテキスト入力フィールドに文字列「 」(アポストロフィなし)を入力し、プログラムは文字列連結ステートメントを使用して、3つの断片、ユーザー入力「」、およびから上記のSQLステートメントを形成しました。[ 11 ]select*frompersonwherename='susan'andage=2
susanここで、攻撃者が「 」を入力する代わりに「 」を入力したと想像してみてください。[ 11 ]'or1=1;--
プログラムは、 の 3 つの断片、 のユーザー入力、 および と同じ文字列連結アプローチを使用して、ステートメント を構築します。多くのデータベースは、コメントを示すため、 '--' 文字列の後のテキストを無視します。SQL コマンドの構造は となり、年齢が 2 の 'susan' という名前の行だけでなく、すべての人物行が選択されます。攻撃者は、データ コンテキストを終了してコマンド コンテキストに入るデータ文字列を作成することに成功しました。[ 11 ]select*frompersonwherename=''or1=1;--'andage=2select*frompersonwherename=''or1=1;--' and age = 2select*frompersonwherename=''or1=1;
SQLインジェクションの根本原因はすべて同じですが、それを悪用する手法は様々です。以下にそのいくつかを紹介します。
プログラムが以下の文字列代入コマンドを使用してSQL文を作成すると想像してください 。
varstatement="SELECT * FROM users WHERE name = '"+userName+"'";
このSQLコードは、指定されたユーザー名のレコードをユーザーテーブルから取得するように設計されています。しかし、悪意のあるユーザーが「userName」変数を特定の方法で操作した場合、SQL文はコード作成者の意図した以上の動作をする可能性があります。たとえば、「userName」変数を次のように設定した場合です。
' OR '1'='1
またはコメントを使用してクエリの残りの部分をブロックすることもできます(SQLコメントには3種類あります[ 12 ])。3行すべて末尾にスペースがあります。
' OR '1'='1' -- ' OR '1'='1' { ' OR '1'='1' /*親言語によって、以下のいずれかのSQL文をレンダリングします。
SELECT * FROM users WHERE name = '' OR '1' = '1' ;SELECT * FROM users WHERE name = '' OR '1' = '1' -- ';このコードが認証手順で使用される場合、この例は、コーダーが意図した特定のユーザー名からではなく、すべてのユーザーからすべてのデータフィールド(*)の選択を強制するために使用できます。なぜなら、「1」=「1」の評価は常に真となるからです。
以下のステートメントの「userName」の値は、複数のステートメントを許可するAPIを使用して、「users」テーブルの削除と「userinfo」テーブルからのすべてのデータの選択(実質的にすべてのユーザーの情報を明らかにする)を引き起こします。
a';DROPTABLEusers;SELECT*FROMuserinfoWHERE't'='t
この入力により、最終的なSQL文が以下のように指定されます。
SELECT * FROM users WHERE name = 'a' ; DROP TABLE users ; SELECT * FROM userinfo WHERE 't' = 't' ;ほとんどのSQL Serverの実装では、このように1回の呼び出しで複数のステートメントを実行できますが、PHPのmysql_query()関数など一部のSQL APIでは、セキュリティ上の理由からこれが許可されていません。これにより、攻撃者が完全に独立したクエリを挿入することは防げますが、クエリを改変することは防げません。
ブラインド SQL インジェクションは、Web アプリケーションが SQL インジェクションに対して脆弱であるが、インジェクションの結果が攻撃者には見えない場合に使用されます。脆弱性のあるページはデータを表示するページではないかもしれませんが、そのページに対して呼び出される正当な SQL ステートメントに挿入された論理ステートメントの結果に応じて異なる表示になります。この種の攻撃は、従来、回復したビットごとに新しいステートメントを作成する必要があり、その構造によっては、攻撃が多数の失敗したリクエストで構成される可能性があるため、時間のかかるものと考えられていました。最近の進歩により、各リクエストで複数のビットを回復できるようになり、失敗したリクエストがなくなり、より一貫性のある効率的な抽出が可能になりました。[ 13 ]脆弱性の場所とターゲット情報が確立されると、これらの攻撃を自動化できるツールがいくつかあります。[ 14 ]
ブラインドSQLインジェクションの一種として、データベースに通常のアプリケーション画面上の論理式を強制的に評価させるものがあります。例えば、書籍レビューサイトはクエリ文字列を使用して表示する書籍レビューを決定します。そのため、URLによってhttps://books.example.com/review?id=5サーバーはクエリを実行することになります。
SELECT * FROM bookreviews WHERE ID = '5' ;これにより、テーブルbookreviewsに保存されているID 5のレビューのデータを使用してレビューページが埋められます。クエリは完全にサーバー上で実行され、ユーザーはデータベース、テーブル、フィールドの名前もクエリ文字列も知りません。ユーザーは上記のURLが書籍レビューを返すことしかわかりません。ハッカーはURLとを読み込むことができ、これによりクエリが発生する可能性があります。https://books.example.com/review?id=5' OR '1'='1https://books.example.com/review?id=5' AND '1'='2
SELECT * FROM bookreviews WHERE ID = '5' OR '1' = '1' ; SELECT * FROM bookreviews WHERE ID = '5' AND '1' = '2' ;それぞれ。元のレビューが「1=1」URLで読み込まれ、「1=2」URLから空白またはエラーページが返され、返されたページが入力が無効であることをユーザーに警告するように作成されていない、つまり入力テストスクリプトによって捕捉されていない場合、クエリがどちらの場合も正常に通過する可能性が高いため、サイトはSQLインジェクション攻撃に対して脆弱である可能性が高い。ハッカーは、サーバーで実行されているMySQLのバージョン番号を明らかにするように設計されたこのクエリ文字列を実行する可能性があります。これにより、MySQL 4を実行しているサーバーでは書籍レビューが表示され、それ以外の場合は空白またはエラーページが表示されます。ハッカーは、クエリ文字列内のコードを使用して目的を直接達成したり、サーバーからより多くの情報を取得して別の攻撃経路を発見したりすることができます。[ 15 ] [ 16 ]https://books.example.com/review?id=5ANDsubstring(@@version,1,INSTR(@@version,'.')-1)=4
二次SQLインジェクションは、アプリケーションがユーザーからの直接入力に対してのみSQLを保護し、システムに既に保存されているデータに対しては保護ポリシーを緩めている場合に発生します。そのため、このようなアプリケーションはユーザー入力を安全に処理して問題なく保存できますが、悪意のあるSQL文も保存してしまいます。そして、そのアプリケーションの別の部分がSQLインジェクションから保護されていないクエリでそのデータを使用すると、この悪意のあるSQL文が実行されてしまう可能性があります。この攻撃には、送信された値が後々どのように使用されるかについてのより深い知識が必要です。自動化されたWebアプリケーションセキュリティスキャナーでは、この種のSQLインジェクションを容易に検出することはできず、攻撃が試みられている証拠を探す場所を手動で指示する必要があるかもしれません。
このような攻撃から保護するためには、データソースに関わらず、すべてのSQL処理が均一に安全でなければならない。
SQLインジェクションはよく知られた攻撃であり、確立されたセキュリティ対策で軽減できます。しかし、2015年に英国の通信会社TalkTalkに対して行われたサイバー攻撃では、SQLインジェクションの脆弱性が悪用され、約40万人の顧客の個人データが侵害されました。BBCは、セキュリティ専門家が大手企業がこのような攻撃に対して脆弱なままであることに驚きを表明したと報じました。[ 17 ]
攻撃者が悪意のある SQL コードをデータベース クエリに挿入するのを防ぐことで SQL インジェクションのリスクを軽減するためのさまざまな防御策が存在します。OWASP が概説している主要な軽減戦略には、パラメータ化クエリ、入力検証、最小権限アクセス制御などがあり、これらはユーザー入力が SQL クエリを変更したり、意図しないコマンドを実行したりする能力を制限します。[ 4 ]予防策に加えて、検出技術は潜在的な SQL インジェクションの試みを特定するのに役立ちます。パターン マッチング、ソフトウェア テスト、文法分析などの手法は、クエリ構造とユーザー入力を調べて、インジェクションの試みを示す可能性のある異常を検出します。[ 2 ]
ほとんどの開発プラットフォームは、ユーザー入力をSQLクエリに埋め込むのではなく、安全に処理するために、プレースホルダーまたはバインド変数とも呼ばれるパラメータ化されたステートメントをサポートしています。これらのプレースホルダーは、定義された型の値のみを格納し、入力がクエリ構造を変更することを防ぎます。その結果、SQLインジェクションの試みは、実行可能なコードではなく、予期しない入力として処理されます。パラメータ化されたクエリでは、SQLコードはユーザー入力とは分離されたままであり、各パラメータは個別の値として渡されるため、SQLステートメントの一部として解釈されることはありません。[ 4 ]
許可リスト入力検証は、明示的に定義された入力のみが受け入れられることを保証し、インジェクション攻撃のリスクを軽減します。既知の悪意のあるパターンをブロックしようとしますが回避される可能性がある拒否リストとは異なり、許可リストは有効な入力を指定し、それ以外のすべてを拒否します。このアプローチは、日付や電子メールアドレスなどの構造化データに対して特に効果的で、厳格な検証ルールを適用できます。入力検証だけでは SQL インジェクションやその他の攻撃を防ぐことはできませんが、SQL クエリに到達する前に不正な入力を識別してフィルタリングすることで、追加の保護として機能します。[ 4 ] [ 18 ]
OWASPによると、最小権限の原則は、データベース アカウントに必要最小限の権限のみを持たせることで、SQL インジェクションのリスクを軽減するのに役立ちます。読み取り専用アカウントには変更権限を与えてはならず、アプリケーション アカウントには管理者権限を与えてはなりません。データベース権限を制限することは、このアプローチの重要な要素です。システム テーブルへのアクセスを制限し、ユーザー ロールを制限することで、SQL インジェクション攻撃のリスクを低減できます。認証やデータ変更など、異なる機能ごとにデータベース ユーザーを分離することで、SQL インジェクション攻撃による潜在的な被害をさらに軽減できます。[ 4 ]
ウェブアプリケーションのデータベースログインにおけるデータベース権限を制限することで、SQLインジェクションの脆弱性による影響をさらに軽減できます。重要なシステムテーブルに対するSELECT権限を制限するなど、アカウントに必要なアクセス権限のみを付与することで、潜在的な攻撃を抑制できます。
Microsoft SQL Serverでは、システム テーブルへの SELECT アクセスを制限することで、データベース スキーマの変更や悪意のあるスクリプトの挿入を試みる SQL インジェクション攻撃を防ぐことができます。たとえば、次のアクセス許可は、データベース ユーザーがシステム オブジェクトにアクセスできないように制限します。
sys.sysobjectsに対するWebDatabaselogonの選択を拒否します。sys.objectsに対するWebDatabaselogonの選択を拒否します。sys.tablesに対するWebDatabaselogonの選択を拒否します。sys.viewsに対するWebDatabaselogonの選択を拒否します。sys.packagesに対するWebDatabaselogonの選択を拒否します。オブジェクトリレーショナルマッピング(ORM)フレームワークは、リレーショナルデータベースとやり取りするためのオブジェクト指向インターフェースを提供します。ORMは通常、SQLインジェクションに対する組み込みの保護機能を提供しますが、適切に実装されていない場合は脆弱になる可能性があります。ORMが生成するクエリの中には、サニタイズされていない入力を許容するものがあり、インジェクションのリスクにつながります。さらに、多くのORMでは開発者が生のSQLクエリを実行できますが、これを不適切に処理するとSQLインジェクションの脆弱性を引き起こす可能性があります。[ 19 ] [ 20 ]
文字列エスケープは、SQLインジェクションに対する主要な防御策としては一般的に推奨されていません。OWASPはこのアプローチを「他の防御策に比べて脆弱」と表現し、すべての状況で有効とは限らないと指摘しています。代わりにOWASPは、SQLインジェクションのリスクを軽減するためのより信頼性の高い方法として、「パラメータ化クエリ、ストアドプロシージャ、またはクエリを自動的に構築するオブジェクトリレーショナルマッパー(ORM)」の使用を推奨しています。[ 4 ]
インジェクションを防ぐ従来の方法の 1 つは、すべてのデータを引用符付き文字列として追加し、そのデータ内の SQL 文字列で特別な意味を持つすべての文字をエスケープすることです。 [ 21 ] SQL DBMS のマニュアルには、どの文字が特別な意味を持つかが説明されており、変換が必要な文字の包括的なブラックリストを作成できます。たとえば、文字列パラメータ内の単一引用符 ( ) のすべての出現箇所の前にバックスラッシュ ( ) を付ける必要があります。これにより、データベースは単一引用符が特定の文字列の一部であり、終端文字ではないと認識します。PHPのMySQLiモジュールは、 MySQL のセマンティクスに従って文字列をエスケープする関数を提供します。次の例では、username は文字列パラメータであるため、文字列エスケープによって保護できます。'\mysqli_real_escape_string()
$mysqli = new mysqli ( 'hostname' , 'db_username' , 'db_password' , 'db_name' ); $query = sprintf ( "SELECT * FROM `Users` WHERE UserName='%s'" , $mysqli -> real_escape_string ( $username ), $mysqli -> query ( $query );さらに、すべてのデータを文字列リテラルとしてSQLに追加できるわけではありません(MySQLのLIMIT句の引数[ 22 ]やテーブル/列名[ 23 ]など)。この場合、文字列関連の特殊文字をエスケープしても何の役にも立たず、結果としてSQLがインジェクション攻撃に対して脆弱なままになります。
SQL インジェクションとは、悪意のあるコードを文字列に挿入し、それを解析および実行のために SQL Server インスタンスに渡す攻撃です。SQL ステートメントを構築するプロシージャはすべて、インジェクションの脆弱性についてレビューする必要があります。なぜなら、SQLi Server は受信した構文的に有効なクエリをすべて実行するからです。熟練した執念深い攻撃者であれば、パラメータ化されたデータでさえ操作される可能性があります。
{{cite web}}: CS1 maint: 数値名: 著者リスト (リンク){{cite web}}: CS1メンテナンス: アーカイブサービスは非推奨になりました (リンク)