パラメータは本当にSQLインジェクションを防ぐのに十分ですか?


83

私は同僚とここ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パラメータの値を設定します。


パラメータの意味を明確にする必要があります(Jonathan Lefflerが指摘したように)-ストアドプロシージャパラメータを考えていましたが、それもありますか?parmsと{0} parms ...
Steven A. Lowe

言うのははるかに簡単です。クエリを作成するために連結を使用しません。

タグはasp.netなので、Webアプリケーションを構築していると思います。この場合、XSS攻撃、そしておそらく他の攻撃にも注意を払う必要があります
Spikolynn 2009年

回答:


50

プレースホルダーは注射を防ぐのに十分です。バッファオーバーフローを受け入れる可能性はまだありますが、これはSQLインジェクションとはまったく異なる種類の攻撃です(攻撃ベクトルはSQL構文ではなく、バイナリになります)。渡されたパラメータはすべて適切にエスケープされるため、攻撃者が「ライブ」SQLのように扱われるデータを渡す方法はありません。

プレースホルダー内で関数を使用することはできません。また、プレースホルダーはエスケープされて文字列リテラルとして引用されるため、列名またはテーブル名として使用することはできません。

ただし、動的クエリ内で文字列連結の一部としてパラメータを使用する場合、文字列はエスケープされずにリテラルになるため、インジェクションに対して脆弱です。パラメータに他のタイプ(整数など)を使用するのは安全です。

とは言うものの、use inputを使用してのような値を設定している場合、security_level誰かが自分自身をシステムの管理者にして、誰でも自由に使えるようにすることができます。しかし、これは基本的な入力検証であり、SQLインジェクションとは何の関係もありません。


重要な点は、@ mikekidderが引用している記事でも指摘されている、Steve Loweの回答によって提起された問題を理解することです。アプリケーション内であろうとサーバー内であろうと、動的SQLがどこにあっても注意する必要があります。動的SQLは危険ですが、安全にすることができます。
ジョナサンレフラー

「攻撃者が「ライブ」SQLのように扱われるデータを渡す方法はありません」。-これは完全に真実ではありません。以下の例を参照してください。
Booji Boy

以下のすべての例は、パラメータを受け入れるSQLコードを意味する「パラメータ化されたクエリ」を定義しています。通常の定義は、DBMSパラメータコレクションを使用するクエリです。DBMSのバグを除けば、この後者の手法はSQLインジェクションを防ぎます。
HTTP 410

2
私はすべてのリンクを読みました。DBMSParametersコレクションに対するインジェクション攻撃が機能していることを示すリンクを引用してください。実際、あなたが投稿したリンクでは、このアプローチをSQLインジェクションの無効化と具体的に言及しています(「タイプセーフなSQLパラメーターの使用」を参照)。
HTTP 410

こんにちは!その答えを証明するために、OracleSQL文法またはそのようなものへのリンクを提供していただけませんか。私はそれを理解し、あなたに絶対に同意しますが、ドキュメント、文法などへの公式リンクがあると素晴らしいでしょうBestRegards、Raimbek
Raimbek Rakhimbek

13

いいえ、未検証のデータを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式全体を動的に記述するなど、他の構文に関しては、より複雑な問題です。


12

このスレッドでは、「パラメーター化されたクエリ」の定義について混乱が生じているようです。

  • パラメータを受け入れるストアドプロシージャなどのSQL。
  • DBMSパラメータコレクションを使用して呼び出されるSQL。

前者の定義を考えると、リンクの多くは実際の攻撃を示しています。

しかし、「通常の」定義は後者です。その定義を考えると、私は機能するSQLインジェクション攻撃を知りません。ないという意味ではありませんが、まだ見ていません。

コメントから、私は自分自身を十分に明確に表現していないので、うまくいけばより明確になる例を次に示します。

このアプローチ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();
}

パラメータを受け入れるプロシージャではなく、DBMSパラメータコレクションの意味を明確にできますか?
Rune Grimstad

ルーン、このリンクの「タイプセーフなSQLパラメータの使用」セクションをお読みください
HTTP 410

私の回答は、アップデートで編集される前のルーンの元の質問に対するものでした。
mikekidder 2008年

SQLインジェクションに関するmsdn-articleを読んで読み直しましたが、ストアドプロシージャが使用するパラメーターと、動的クエリが使用するパラメーターの間にどのような違いがあるのか​​まだわかりません。動的クエリが動的であるという事実は別として。あなたはまだパラメータをバインドする必要がありますよね?
Rune Grimstad

違いを生むのはバインディングです。パラメータを使用してストアドプロシージャを直接呼び出す場合、入力フィルタリングは行われません。ただし、(たとえば).NETのSqlCommandパラメータコレクションを使用してバインドすると、すべてのパラメータがフィルタリングされ、プレーンテキストとして扱われます。
HTTP 410

10

動的クエリの作成に使用される文字列型(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インジェクション攻撃ベクトルです。

@ p1が、ユーザーが介入する能力なしにプログラムで作成されている場合、それは潜在的なSQLインジェクション攻撃ベクトルではありません。


番号; 重要なのは、DBMSに渡される文字列はSQLステートメントの一部ではないということです。したがって、文字列の値は、SQLの解釈に影響を与えることはなく、SQLによって参照される値にのみ影響します。
ジョナサンレフラー

それが私がパラメータを見る方法でもあります。彼らはこの問題を防ぐことになっています。
Rune Grimstad

2
たとえば、文字列を使用してsp_executeSql(SQLサーバー)などを実行するspに文字列を渡す場合、SQLインジェクションのリスクがあります。
alexmac 2008年

@Steven:これはSQLのパラメーターではありません。文字列の連結の代わりにプレースホルダー(疑問符)が必要になります。また、SQLでは、プレースホルダーでテーブル名を指定することはできません。これは純粋なSQLインジェクションの脆弱性であり、元々の問題です。
ジョナサンレフラー

@Steven:「パラメータ」という用語が頻繁にオーバーロードされている可能性があります。:D
Jonathan Leffler

6

バッファオーバーフローはSQLインジェクションではありません。

パラメータ化されたクエリは、SQLインジェクションに対して安全であることを保証します。SQLサーバーにバグの形で悪用される可能性がないことを保証するものではありませんが、それを保証するものはありません。


2

パーミッションはテーブルレベルである必要があるため、何らかの形または形式で動的SQLを使用する場合、データは安全ではありません。はい、その特定のクエリからのインジェクション攻撃の種類と量を制限しましたが、ユーザーがシステムへの道を見つけた場合にユーザーが取得できるアクセスを制限していません。また、内部ユーザーがアクセスしてはならないものに完全にアクセスできます。詐欺を犯したり、個人情報を盗んで販売したりするため。あらゆるタイプの動的SQLは危険な行為です。非動的なストアドプロシージャを使用する場合は、プロシージャレベルでアクセス許可を設定でき、プロシージャで定義されている以外のユーザーは何もできません(もちろんシステム管理者を除く)。


したがって、ここでの教訓は、動的SQLを使用する必要がある場合は、ストアドプロシージャ内でのみ使用することです。+1良いアドバイス!
スティーブンA.ロウ

1
いいえ-ストアドプロシージャの動的SQLは、検証されていないデータを動的クエリに補間することにより、SQLインジェクションの欠陥を引き起こす可能性があります。
ビルカーウィン

ここでの教訓は、動的SQlを決して使用しないことです
HLGEM

@ HLGEM-そうです、そして自動車は交通事故に巻き込まれているので、私たちは決して自動車を使うべきではありません。
ビルカーウィン

ただし、ストアドプロシージャの動的SQLは、(デフォルトでは)呼び出し元の権限で実行されます。これは、ストアドプロシージャの所有者の権限で実行される静的SQLとは異なります。これは重要な違いです。
HTTP 410

1

ストアドプロシージャは、オーバーフロー/切り捨てを介した特殊なタイプのSQLインジェクションに対して脆弱である可能性があります。「データ切り捨てによって有効化されたインジェクション」を参照してください。

http://msdn.microsoft.com/en-us/library/ms161953.aspx


この記事を詳しく読むと、SQLServerのParametersコレクションを使用することでこの攻撃を防ぐことができます。これが「パラメータ化されたクエリ」の通常の定義です。DBMSのParametersコレクションを使用します。
HTTP 410

1

パラメータを使用すると、文字列を簡単に保存できることを覚えておいてください。ポリシーがない場合はユーザー名を言うと、 ");テーブルユーザーを削除します;-"

これ自体は害を及ぼすことはありませんが、その日付がアプリケーションのどこでどのように使用されるかをよく知っています(たとえば、Cookieに保存され、後で他のことを行うために取得されます。


1

例として動的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'
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.