クエリ1と2の両方で、テキストボックスのテキストがデータベースに挿入されます。ここでパラメーター化されたクエリの重要性は何ですか?
txtTagNumber
をクエリパラメーターとして渡す
SqlCommand cmd = new SqlCommand("INSERT INTO dbo.Cars " +"VALUES(@TagNbr);" , conn);
cmd.Parameters.Add("@TagNbr", SqlDbType.Int);
cmd.Parameters["@TagNbr"].Value = txtTagNumber.Text;
クエリを構築する前にtxtTagNumber
を整数に変換する
int tagnumber = txtTagNumber.Text.ToInt16(); /* EDITED */
INSERT into Cars values(tagnumber.Text); /* then is it the same? */
また、ここでは、正規表現の検証を使用して、不正な文字の挿入を停止します。
パラメータ化されたクエリは、SQLクエリを実行する前に引数を適切に置換します。クエリの意味を変更する「ダーティ」な入力の可能性を完全に取り除きます。つまり、入力にSQLが含まれている場合、SQLが結果のステートメントに挿入されることがないため、実行されるものの一部になることはできません。
可能性のあるパラメーターにsqlが含まれ、文字列が本来のように処理されない場合、sqlインジェクションが発生します
例えば:
var sqlquerywithoutcommand = "select * from mytable where rowname = '" + condition+''";
条件は、リクエスト内のユーザーからの文字列です。条件が悪意がある場合は、たとえば次のように言います。
var sqlquerywithoutcommand = "select * from mytable where rowname = '" + "a' ;drop table mytable where '1=1"+"'";
悪意のあるスクリプトを実行してしまう可能性があります。
しかし、パラメータを使用すると、文字列文字をエスケープする可能性のある文字が入力から削除されます...
何が入っていても、インジェクトスクリプトを実行できないようにすることができます。
コマンドオブジェクトをパラメータとともに使用すると、実際に実行されるSQLは次のようになります
select * from mytable where rowname = 'a'';drop table mytable where 1=1'''
本質的に、rowname = a '; drop table mytable where 1 = 1'の行を探し、残りのスクリプトを実行しません
動的SQLクエリを想像してください
sqlQuery='SELECT * FROM custTable WHERE User=' + Username + ' AND Pass=' + password
簡単なSQLインジェクションは、ユーザー名を
' OR 1=1--
として入力するだけです。これにより、SQLクエリが効果的に作成されます。sqlQuery='SELECT * FROM custTable WHERE User='' OR 1=1-- ' AND PASS=' + password
これは、ユーザー名が空白( '')または1 = 1(ブール値)で、trueに等しいすべての顧客を選択することを意味します。次に-を使用して、クエリの残りの部分をコメント化します。したがって、これはすべての顧客テーブルを出力するか、または必要に応じて何でも実行します。ログインすると、最初のユーザーの特権(多くの場合は管理者)でログインします。
現在、パラメータ化されたクエリは、次のようなコードを使用して異なる方法で実行します。
sqlQuery='SELECT * FROM custTable WHERE User=? AND Pass=?'
parameters.add( "User"、username)parameters.add( "Pass"、password)
ここで、ユーザー名とパスワードは、関連する入力されたユーザー名とパスワードを指す変数です
この時点で、あなたは考えているかもしれませんが、これは何も変えません。もちろん、ユーザー名フィールドにNobody OR 1 = 1 '---
sqlQuery='SELECT * FROM custTable WHERE User=Nobody OR 1=1'-- AND Pass=?'
そして、これは有効な議論のように思えます。しかし、あなたは間違っているでしょう。
パラメータ化されたクエリが機能する方法は、sqlQueryがクエリとして送信され、データベースがこのクエリの処理内容を正確に認識し、その値が設定された場合のみユーザー名とパスワードを値として挿入することです。これは、データベースがクエリの処理内容をすでに知っているため、クエリに影響を与えることができないことを意味します。そのため、この場合、
"Nobody OR 1=1'--"
のユーザー名と空のパスワードを検索しますが、これは間違っているはずです。
パラメータ化されたクエリがすべてを処理します-なぜ問題になりますか?
パラメータ化されたクエリを使用すると、一般的な注入に加えて、すべてのデータ型、数値(intおよびfloat)、文字列(埋め込み引用符付き)、日付と時刻(。インバリアントカルチャを使用すると、クライアントは予期しない日付形式のマシンに移動します)。
なぜそう感じるのかは非常に理解しやすい。
sqlQuery = "select * from users where username='+username+';"
対
sqlQuery = "select * from users where username=@username;"
上記のクエリは両方とも同じことをしているように見えますが、実際にはそうではありません。
前者はクエリに入力を使用し、後者はクエリを決定しますが、クエリの実行中に入力をそのまま置換します。
より明確にするために、パラメータの値は、変数のメモリが格納されているスタック上のどこかに配置され、必要なときに検索に使用されます。
したがって、ユーザー名の入力として' OR '1'='1
を指定すると、前者は動的 sqlクエリ文字列sqlQuery
の一部として新しいクエリまたはクエリを作成します実行されました。
同じ入力で、後者はusername
テーブルのusers
フィールドで、クエリ文字列_staticallyで指定されたクエリを使用して' OR '1'='
を検索しますsqlQuery
単に統合するために、これはパラメータを使用してクエリを作成する方法です。
SqlCommand command = new SqlCommand(sqlQuery,yourSqlConnection);
SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "@username";
parameter.Value = "xyz";
command.Parameters.Add(parameter);
パラメータ化されたクエリにより、クライアントはクエリテキストとは別にデータを渡すことができます。ほとんどの場合、テキストのない場所では、検証とエスケープを行います。もちろん、パラメーター化は他の種類のインジェクションには役立ちませんが、パラメーターが個別に渡されるため、実行テキストクエリとして使用されません。
よく似ているのは、バッファオーバーフローから保護するために、最新のプロセッサとオペレーティングシステムのほとんどで使用される「最近の」実行ビットです。バッファオーバーフローは引き続き許可されますが、挿入されたデータの実行は防止されます。