SQL語句のようにプリペアドステートメントの使用どうして必要になりますか¶
SQL注入SQL注入攻撃対策¶
SQLを用いてデータベースを扱うWebアプリケーションは、SQL注入を許さないようにする必要がある。SQL注入攻撃対策のうち、まずは実装における対策について述べる。
文脈に応じた特殊記号対策はコマンド注入攻撃対策と同様である。加えて、プリペアードステートメントの使用や言語の選択による対策を説明する。
- SQL注入
「SQL注入(SQL injection)」は、パラメータを埋め込んでSQL文を組み立てる場合、そのパラメータに特殊記号(記号)を含ませたSQLコマンドを与えることによって、 データベースの不正操作が可能となってしまう問題である。
- SQL注入攻撃のメカニズム
ここに、次のようなSQL文を使用したログイン判定プログラムがあるとする。
1 | SELECT uid FROM account_table WHERE uid='ユーザID' AND pw='パスワード |
このSQL文は、ユーザID(uid)とパスワード(pw)を入力パラメータとして受け取り、その組み合わせをデータベーステーブル(account_table)から検索する。 そして、該当するレコードがあった場合に、そのユーザID(uid)を返す処理となっている。このSQL文以降の処理は、ユーザIDが返った場合にのみログインを可能とする内容となっている。
ここで、ユーザIDに「' OR 1=1--」という文字列が与えられた場合は、次のようなSQL文が組み立てられてしまう。
1 | SELECT uid FROM account_table WHERE uid='' OR 1=1--' AND pw='任意の文字列 |
実は、与えられた文字列「' OR 1=1--」には、次のような意味がある。 ' : ひとつ前の「'」と対となり、文字列定数を終わらせる OR 1=1 : uidの値に関係なく、検索条件を、真とさせる
: それ以降の内容をコメントとして無視させる このため、この文字列をパラメータとして与えられた場合は、ユーザIDが常に返ってくるため、本来ログインを許可されていないユーザもログインが可能となってしまうのである。
- SQL注入攻撃に伴って想定される被害
SQL注入攻撃の脅威は、攻撃者がSQLで利用できる機能を全て操作可能となってしまうことであり、具体的には次の被害が挙げられる。:
- 情報の流出 非公開情報(個人情報等)の漏えい等
- 情報の改ざん データベースに蓄積された情報(商品価格やパスワード等)の改ざん等
- データの破壊 蓄積されたデータの消去やデータベーステーブル自体の破壊等
-
サーバの乗っ取り ストアドプロシージャを利用したサーバの不正操作等
-
コーディイングによる対策
SQL注入攻撃を迎撃する対策の実装について、この攻撃パターンのデータフローに沿って説明する。まず、入力データの範囲を仕様によって絞り込める場合 * 入力値チェックの徹底 * %{color:red}プリペアドステートメントの使用% * 文脈に応じた特殊記号対策
プリペアドステートメントの使用¶
これは、入力データの部分を埋め込んで文字列を組み立てる際に、文字列連結演算を使用せずに、プリペアドステートメントを使用して、SQL文の組み立てを行う方法である。
プリペアドステートメントは、プレースホルダと値埋め込みAPIから成る解析済みのSQL文であり、コード中のプレースホルダ(予約場所)に入力データを割り当てる機能(バインドメカニズム)である。
より成熟したデータベースの多くは、プリペアドステートメントという 概念をサポートしています。プリペアドステートメントとはいったい何の ことでしょう? これは、実行したい SQL をコンパイルした 一種のテンプレートのようなものです。パラメータ変数を使用することで SQL をカスタマイズすることが可能です。プリペアドステートメントには 2 つの大きな利点があります。
クエリのパース (あるいは準備) が必要なのは最初の一回だけで、 同じパラメータ (あるいは別のパラメータ) を指定して何度でも クエリを実行することができます。クエリを実行するには、準備として クエリの解析やコンパイル、そして実行プランの最適化が行われます。 クエリが複雑になると、この処理には時間がかかるようになります。 同じクエリを異なったパラメータで何度も実行すると、アプリケーションの 動作は目に見えて遅くなるでしょう。 プリペアドステートメントを使用すると、この 解析/コンパイル/最適化 の繰り返しを避けることができます。 端的に言うと、プリペアドステートメントは使用するリソースが少なくいため 高速に動作するということです。 プリペアドステートメントに渡すパラメータは、引用符で括る必要は ありません。それはドライバが自動的に行います。 アプリケーションで明示的にプリペアドステートメントを使用するように すれば、SQL インジェクションは決して発生しません (しかし、もし信頼できない入力をもとにクエリの他の部分を構築している のならば、その部分に対するリスクを負うことになります)。 プリペアドステートメントは非常に有用な機能なので、もしドライバが サポートしていなくても、例外的に PDO がこの機能をエミュレートします。 これにより、データベースの機能にかかわらず同じ仕組みで データベースへのアクセスができることが保証されます。