私は同僚とここでSO SQLクエリ、特に.NETアプリケーションでパラメータを使用することの良さについて説教しています。私は、 SQLインジェクション攻撃に対する耐性を与えます。
しかし、私はこれが本当かどうか疑問に思っています。パラメーター化されたクエリに対して成功する既知のSQLインジェクション攻撃はありますか?たとえば、サーバーでバッファオーバーフローを引き起こす文字列を送信できますか?
もちろん、Webアプリケーションの安全性を確保するために他の考慮事項(ユーザー入力などをサニタイズするなど)がありますが、今はSQLインジェクションを考えています。 MsSQL 2005および2008に対する攻撃には特に興味があります。これらは私の主要なデータベースですが、すべてのデータベースが興味深いものです。
編集:パラメーターとパラメーター化されたクエリの意味を明確にします。パラメーターを使用することにより、文字列でsqlクエリを作成する代わりに「変数」を使用することを意味します。
したがって、これを行う代わりに:
SELECT * FROM Table WHERE Name = 'a name'
これを行います:
SELECT * FROM Table WHERE Name = @Name
次に、クエリ/コマンドオブジェクトの@Nameパラメータの値を設定します。
プレースホルダーは注入を防ぐのに十分です。あなたはまだバッファオーバーフローに対してオープンになっているかもしれませんが、それはSQLインジェクションとはまったく異なる種類の攻撃です(攻撃ベクトルはSQL構文ではなくバイナリです)。渡されたパラメーターはすべて適切にエスケープされるため、攻撃者が「ライブ」SQLのように扱われるデータを渡す方法はありません。
プレースホルダー内で関数を使用することはできません。また、プレースホルダーは文字列リテラルとしてエスケープおよび引用されるため、列名またはテーブル名として使用することはできません。
ただし、ダイナミッククエリ内でstring concatenationの一部としてparametersを使用すると、文字列はエスケープされずリテラルになるため、インジェクションに対して脆弱です。パラメーターに他のタイプ(整数など)を使用しても安全です。
つまり、入力を使用してsecurity_level
などの値を設定している場合、誰かが自分のシステムの管理者になり、自由に使えるようになる可能性があります。ただし、これは単なる基本的な入力検証であり、SQLインジェクションとは関係ありません。
このスレッドでは、「パラメーター化されたクエリ」の定義に関して混乱が生じているようです。
前者の定義を考えると、リンクの多くは実際の攻撃を示しています。
しかし、「通常の」定義は後者です。その定義を考えると、機能するSQLインジェクション攻撃については知りません。それは、それがないという意味ではありませんが、私はまだ見ていません。
コメントから、私は十分に明確に自分自身を表現していませんので、願わくばより明確になる例があります:
このアプローチis SQLインジェクションに対してオープン
exec dbo.MyStoredProc 'DodgyText'
このアプローチではない SQLインジェクションに対してオープン
using (SqlCommand cmd = new SqlCommand("dbo.MyStoredProc", testConnection))
{
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter newParam = new SqlParameter(paramName, SqlDbType.Varchar);
newParam.Value = "DodgyText";
.....
cmd.Parameters.Add(newParam);
.....
cmd.ExecuteNonQuery();
}
いいえ、未検証のデータをSQLクエリに挿入すると、常にSQLインジェクションのリスクがあります。
クエリパラメータは、リテラル値をSQL構文から分離することにより、このリスクを回避するのに役立ちます。
'SELECT * FROM mytable WHERE colname = ?'
それは問題ありませんが、クエリ値を使用できない動的SQLクエリにデータを補間する他の目的があります。これは、SQL値ではなく、テーブル名、列名、式、またはその他の構文であるためです。
'SELECT * FROM ' + @tablename + ' WHERE colname IN (' + @comma_list + ')'
' ORDER BY ' + @colname'
ストアドプロシージャを使用しているか、アプリケーションコードから動的SQLクエリを直接実行しているかは関係ありません。リスクはまだ残っています。
これらの場合の解決策は、必要に応じて[〜#〜] fieo [〜#〜]を使用することです。
入力のフィルター:補間する前に、データが正当な整数、テーブル名、列名などに見えることを検証します。
エスケープ出力:この場合、「出力」はデータをSQLクエリに入れることを意味します。関数を使用して、SQL式で文字列リテラルとして使用される変数を変換し、文字列内の引用符やその他の特殊文字をエスケープします。また、関数を使用して、テーブル名、列名などとして使用される変数を変換する必要があります。SQL式全体を動的に記述するような他の構文については、より複雑な問題です。
動的クエリの構築に使用される文字列型(varchar、nvarcharなど)のsqlパラメーターは依然として脆弱です。
それ以外の場合、パラメータタイプの変換(たとえば、int、decimal、dateなど)は、パラメータを介してSQLを挿入する試みを排除する必要があります
編集:パラメーター@ p1がテーブル名を意図している例
create procedure dbo.uspBeAfraidBeVeryAfraid ( @p1 varchar(64) )
AS
SET NOCOUNT ON
declare @sql varchar(512)
set @sql = 'select * from ' + @p1
exec(@sql)
GO
ドロップダウンリストから@ p1を選択すると、潜在的なsql-injection攻撃ベクトルになります。
@ p1が、ユーザーが介入する能力なしにプログラムで定式化されている場合、潜在的なSQLインジェクション攻撃ベクトルではありません。
バッファオーバーフローはSQLインジェクションではありません。
パラメータ化されたクエリは、SQLインジェクションに対して安全であることを保証します。 SQLサーバーのバグという形で悪用される可能性がないことを保証するものではありませんが、それを保証するものは何もありません。
権限がテーブルレベルである必要があるため、動的SQLを何らかの形または形式で使用する場合、データは安全ではありません。はい、その特定のクエリからのインジェクション攻撃の種類と量を制限しましたが、ユーザーがシステムへの道を見つけた場合に取得できるアクセスを制限していません。詐欺を犯したり、販売する個人情報を盗むために。あらゆるタイプの動的SQLは危険な行為です。動的でないストアドプロシージャを使用する場合、プロシージャレベルでアクセス許可を設定できます。ユーザーは、プロシージャによって定義されたもの(もちろんシステム管理者を除く)以外は何もできません。
ストアドプロシージャが、オーバーフロー/切り捨てを介して特別なタイプのSQLインジェクションに対して脆弱になる可能性があります。こちらを参照してください。
例として動的SQLを実行できます
DECLARE @SQL NVARCHAR(4000);
DECLARE @ParameterDefinition NVARCHAR(4000);
SELECT @ParameterDefinition = '@date varchar(10)'
SET @SQL='Select CAST(@date AS DATETIME) Date'
EXEC sp_executeSQL @SQL,@ParameterDefinition,@date='04/15/2011'
パラメータを使用すると、文字列を簡単に保存できること、またはポリシーがない場合はユーザー名を言うことができることを覚えておいてください。 "); drop table users;-"
これ自体は害を及ぼすことはありませんが、アプリケーションでその日付がどこでどのように使用されるかをよりよく知っています(たとえば、Cookieに保存され、後で他のことを行うために取得されます)。