96

「誰もが」パラメータ化された SQL クエリを使用して、ユーザー入力のすべての部分を検証することなく、SQL インジェクション攻撃から保護していると聞いています。

これどうやってやるの?ストアド プロシージャを使用する場合、これは自動的に取得されますか?

したがって、これはパラメータ化されていないという私の理解:

cmdText = String.Format("SELECT foo FROM bar WHERE baz = '{0}'", fuz)

これはパラメータ化されますか?

cmdText = String.Format("EXEC foo_from_baz '{0}'", fuz)

または、SQL インジェクションから身を守るために、このようなより広範なことを行う必要がありますか?

With command
    .Parameters.Count = 1
    .Parameters.Item(0).ParameterName = "@baz"
    .Parameters.Item(0).Value = fuz
End With

セキュリティ上の考慮事項以外に、パラメーター化されたクエリを使用する利点はありますか?

更新: この素晴らしい記事は、Grotok による質問の参照の 1 つにリンクされていました。 http://www.sommarskog.se/dynamic_sql.html

4

6 に答える 6

80

EXEC質問の例はパラメーター化されません。このような入力が損傷を引き起こすのを防ぐには、パラメーター化されたクエリ (いくつかの円で準備されたステートメント) が必要です。

';DROP TABLE バー;--

それを変数に入れてみてください(または、テーブルfuzを重視する場合は入れないでください)。barより微妙で有害なクエリも可能です。

Sql Server でパラメーターを使用する方法の例を次に示します。

Public Function GetBarFooByBaz(ByVal Baz As String) As String
    Dim sql As String = "SELECT foo FROM bar WHERE baz= @Baz"

    Using cn As New SqlConnection("Your connection string here"), _
        cmd As New SqlCommand(sql, cn)

        cmd.Parameters.Add("@Baz", SqlDbType.VarChar, 50).Value = Baz
        Return cmd.ExecuteScalar().ToString()
    End Using
End Function

ストアド プロシージャは、SQL インジェクションの防止に貢献していると言われています。ただし、ほとんどの場合、クエリ パラメーターを使用してそれらを呼び出す必要があります。そうしないと、役に立ちません。ストアド プロシージャのみを使用する場合は、アプリケーション ユーザー アカウントの SELECT、UPDATE、ALTER、CREATE、DELETE など (EXEC 以外のほぼすべて) のアクセス許可をオフにして、その方法である程度の保護を得ることができます。

于 2009-02-12T17:55:22.827 に答える
15

間違いなく最後のもの、つまり

それとも、もっと大規模なことをする必要がありますか...? (はい、cmd.Parameters.Add())

パラメーター化されたクエリには、主に次の 2 つの利点があります。

  • セキュリティ: SQL インジェクションの脆弱性を回避する良い方法です
  • パフォーマンス: 異なるパラメーターだけを使用して同じクエリを定期的に呼び出すと、パラメーター化されたクエリによってデータベースがクエリをキャッシュできるようになり、パフォーマンスが大幅に向上します。
  • おまけ: データベース コードの日付と時刻のフォーマットの問題について心配する必要はありません。同様に、英語以外のロケールのマシンでコードを実行する場合、小数点や小数点のコンマの問題は発生しません。
于 2009-02-12T17:58:10.527 に答える
5

これは真にパラメータ化された唯一のものであるため、最後の例を使用したいと考えています。セキュリティ上の懸念 (これはあなたが考えるよりもはるかに一般的です) に加えて、ADO.NET にパラメーター化を処理させるのが最善です。渡す値に一重引用符が必要かどうかはType、各パラメーターを調べないとわからないからです。 .

[編集] ここに例があります:

SqlCommand command = new SqlCommand(
    "select foo from bar where baz = @baz",
    yourSqlConnection
);

SqlParameter parameter = new SqlParameter();
parameter.ParameterName = "@baz";
parameter.Value = "xyz";

command.Parameters.Add(parameter);
于 2009-02-12T17:53:02.473 に答える
2

ほとんどの人は、PHP の PDO や Perl DBI などのサーバー側プログラミング言語ライブラリを介してこれを行います。

たとえば、PDO では次のようになります。

$dbh=pdo_connect(); //you need a connection function, returns a pdo db connection

$sql='insert into squip values(null,?,?)';

$statement=$dbh->prepare($sql);

$data=array('my user supplied data','more stuff');

$statement->execute($data);

if($statement->rowCount()==1){/*it worked*/}

これにより、データベース挿入のためにデータがエスケープされます。

利点の 1 つは、1 つの準備済みステートメントで挿入を何度も繰り返すことができるため、速度が向上することです。

たとえば、上記のクエリでは、ステートメントを 1 回準備してから、一連のデータからデータ配列を作成してループし、->execute を必要な回数だけ繰り返すことができます。

于 2009-02-12T17:57:01.947 に答える
1

コマンド テキストは次のようにする必要があります。

cmdText = "SELECT foo FROM bar WHERE baz = ?"

cmdText = "EXEC foo_from_baz ?"

次に、パラメーター値を追加します。この方法では、変数 fuz が

"x'; delete from foo where 'a' = 'a"

何が起こるかわかりますか?

于 2009-02-12T17:56:05.803 に答える