7

以下のPostgreSQLクエリをアポストロフィを含む値で実行しようとすると、最初のSQLエスケープエラー(長い間延期されていました)が発生しました。O'Brien、FreePascalとLazarusを使用

SQL.Add(format('select * from zones where upper(zn_name) >=  %s and upper(zn_name) < %s order by zn_name',[sQuote(zoneMin), sQuote(zoneMax)]));

上記のクエリでは、SQuoteは文字列を一重引用符で囲む関数です。Lazarus / FreePascalまたはDelphiのSQLクエリパラメータをサニタイズするための標準ライブラリはありますか?

4

1 に答える 1

18

アプリケーションは、SQLインジェクションと呼ばれる深刻なセキュリティ問題に対して脆弱です。http://bobby-tables.com/を参照してください。

確かにO'Brian、エラーが発生しますが、どう');DROP SCHEMA public;--でしょうか。または');DELETE FROM users;--?アプリがスーパーユーザーまたはテーブルを所有するユーザーとして実行されてはならないため、1つ目は機能ないはずですが、実際にそれを実行しようと努力し、多くの場合、本番環境で特権ユーザーを実行するアプリケーション設計者はほとんどいません。2つ目は、ほとんどのアプリケーションで機能します。詳細については、投稿の最後を参照してください。

最も簡単で最善の予防策は、クライアントライブラリでパラメータ化されたステートメント*を使用することです。Delpiについては、次のを参照してください。

To use a prepared statement, do something like this:

query.SQL.Text := 'update people set name=:Name where id=:ID';
query.Prepare;
query.ParamByName( 'Name' ).AsString := name;
query.ParamByName( 'ID' ).AsInteger := id;
query.ExecSQL;

(私はDelphiを使用したことがなく、1995年にPascalコードを最後に作成しました。与えられた例を引用しているだけです)。

現在行っているのは、パラメーターの文字列補間です。とても危険です。これは、 SQLリテラルを引用するための堅牢な関数がある場合にのみ安全に実行できます。この関数は、両端で引用符を付けるだけでなく、他のエスケープ、引用符の二重化なども処理します。これは最後の手段のアプローチです。パラメータ化されたステートメントを使用することを強くお勧めします。


これが私が上で与えた例の拡張です。ユーザー名によるユーザーの完全に通常の挿入を行っているとします。ここで、「Fred」はクライアントによって入力されたユーザー名の例です。

INSERT INTO users ( user_name ) VALUES ('Fred');

これで、不快な人がユーザー名を送信します');DELETE FROM users;--。突然、アプリケーションが実行されます。

INSERT INTO users ( user_name ) VALUES ('');DELETE FROM users;--');

展開すると次のようになります。

INSERT INTO users ( user_name ) VALUES ('');
DELETE FROM users;
--');

つまり、空の文字列を挿入する挿入(ただし、完全に有効なユーザー名を簡単に挿入できます)の後に、DELETE FROM users;ステートメント(のすべての行を削除)、そしてusers何もしないコメントが続きます。スプラット。あなたのデータがあります。


*パラメーター化されたステートメントは、誤ってプリペアドステートメントと呼ばれることがあります。プリペアドステートメントは必ずしもパラメータ化されているわけではなく、パラメータ化されたステートメントは必ずしも準備されていないため、これは正しくありません。多くの言語のデータベースインターフェイスでは、プリペアドステートメントを使用せずにパラメータ化されたステートメントを使用する方法が提供されていないため、混乱が生じています。

于 2012-11-01T04:45:45.430 に答える