ADO とプリペアドステートメント
最近、入力値検査の不備を突いたSQLインジェクションが取りざたされているのを見ていて、Windows上で、共通のAPIによるデータベースへのアクセスを可能にするActiveXコンポーネントADO(ActiveX Data Objects)では、対策を講じられるかどうか不安になって調べてみた。
どうやら、ADOはプリペアドステートメントを利用出来るらしいことが分かった。正確にはMSDNがパラメータクエリと呼んでいるものだけど。
まずは、ADODB.Commandオブジェクトを生成して、現在のコネクションをCommand#ActiveConnectionプロパティに束縛する。これにより、コマンドとコネクションが関連づけられる。
// connect to the database conn = new ActiveXObject("ADODB.Connection"); conn.Open(...); // create a command object cmd = new ActiveXObject("ADODB.Command"); cmd.ActiveConnection = conn;
次はコマンド、具体的にはプリペアドステートメントを定義する。コマンドの種類を表すCommand#CommandTypeプロパティに、コマンドがSQLステートメントであることを表すadCmdText(1)を、コマンドの内容を表すCommand#CommandTextプロパティに、プリペアドステートメントを束縛する。
cmd.CommandType = adCmdText; // = 1; cmd.CommandText = "SELECT * from someTable WHERE someItem = ?";
これだけでは、まだクエリを発行することは出来ない。プリペアドステートメントにあるパラメータマーカーと、コマンドが保持するパラメータコレクションの関連付けが行われていないからだ。Command#CreateParameterメソッドによってParameterオブジェクトを生成し、Command#Parameters#Appendメソッド で、パラメータコレクションにパラメータの追加を行う。
cmd.Parameters.Append(cmd.CreateParameter('someWChar', adWChar, 1, 1024));
最後に、コマンドがプリペアドステートメントであることを表明するために、Command#PreparedプロパティをTrueに設定すれば、準備完了だ。
cmd.Prepared = true;
ステートメントをプリコンパイルする必要がない場合は、Falseでも構わないようだ。大量のクエリを発行する場合は、Trueにしておいた方がいいと思う。
クエリを発行する際のパラメータ設定は以下のようにするようだ。コマンド実行はCommand#Executeメソッドを呼ぶ。
// same as: cmd.Parameters.Item('someWChar') = 'Hello, world!'; cmd('someWChar') = 'Hello, world!'; // execute the command var recordSet = cmd.Execute();
ネイティブでは、パラメータクエリの発行にややこしいイディオムがあった記憶があるけど、こっちは比較的分かりやすいし、使いやすいなぁ。