0

作成する必要のあるアプリケーションがあります。このアプリケーションは、CSV形式のユーザー入力があれば、このCSVを解析して複数の形式に生成する必要があります。これらの形式の1つは、CSVの各行に対する一連のSQL INSERTステートメント(文字列として)です。

(この時点で、CSVを値のリストなどに解析したと想定できるので、それは問題のポイントではありません)

この入力には脆弱性が含まれている可能性があるため、検証およびサニタイズされたINSERTステートメントを生成したいと思います。

私はSqlCommandオブジェクトを作成し、そのパラメーターのリストに値を追加することに精通していますが、同様の質問を見ると、期待どおりに機能していないようです。

では、必要な方法で、サニタイズされたSQLステートメントを文字列として生成する方法はありますか?

編集:これは私がやりたいことの例です。

CSV:

id,name,country
1,Alice,France
2,Bob,Austria
3,Carol,Germany

SQL:

...
INSERT INTO Users (id, name, country) VALUES (1, 'Alice', 'France');
INSERT INTO Users (id, name, country) VALUES (2, 'Bob', 'Austria');
INSERT INTO Users (id, name, country) VALUES (3, 'Carol', 'Germany');
...

CSVにはデータ型が指定されていないため、アプリケーションはそれも決定する必要があります。

4

3 に答える 3

1

変数をどのように保存したかわからないため、:を使用してサンプルデータを使用した完全で可能な実装を示しますList<Dictionary<String, Object>>()

サンプルデータを追加します。

var tableName = "Users";
var records = new List<Dictionary<String, Object>>();
var recordFields = new Dictionary<String, Object>();
recordFields.Add("id", 1);
recordFields.Add("name", "Alice");
recordFields.Add("country", "France");
records.Add(recordFields);
recordFields = new Dictionary<String, Object>();
recordFields.Add("id", 2);
recordFields.Add("name", "Bob");
recordFields.Add("country", "Austria");
records.Add(recordFields);
recordFields = new Dictionary<String, Object>();
recordFields.Add("id", 3);
recordFields.Add("name", "Carol");
recordFields.Add("country", "Germany");
records.Add(recordFields);

パラメータ化された挿入ステートメントを生成します。

using (var con = new SqlConnection(Settings.Default.ConnectionString))
{
    con.Open();
    foreach (var record in records)
    {
        String insertSql = String.Format("INSERT INTO {0} ({1}) VALUES ({2});"
            , tableName
            , String.Join(",", record.Select(r => r.Key))
            , String.Join(",", record.Select(r => "@" + r.Key)));
        using (var insertCommand = new SqlCommand(insertSql, con))
        {
            foreach (var field in record)
            {
                var param = new SqlParameter("@" + field.Key, field.Value);
                insertCommand.Parameters.Add(param);
            }
            insertCommand.ExecuteNonQuery();
        }
    }
}

これは実際にはテストされていないことに注意してください(コンパイルして見栄えがします)が、とにかく役立つはずです。

編集

@Oded:問題は、ダニエルが挿入を実行したくないが、それらを表示/出力/保存したいということだと思います。したがって、生成されたSQLが表示されないため、SqlCommandパラメーターを使用することは適切ではありません。

@Cylindricその通りです

それは不可能であり、矛盾します。withを使用することはできませStringSqlParameters。したがって、後でこれらの挿入を実行する場合は、SQLインジェクションを使用できます。実際にstatemenetsを実行しているときは、上記のコードを使用することをお勧めします。

于 2012-04-25T11:03:51.043 に答える
1

注意点として、それほど答えではありません。これを行うために「古典的な」逃走経路をとる必要があり、本当に安全が必要な場合(つまり、データが信頼できないソースから入ってくる場合)、心配する必要があるのは単純な逃走だけではないことを忘れないでください。

私たちがいつも耳にする基本的なキャラクターのエスケープ:

  • ' -> ''アポストロフィなどは非常に明白で、文書化されています。
  • ;1つのステートメントでの複数のコマンド-DBで常に許可されているわけではありませんが、危険です

ただし、「不正な動作」を解析している場合は、次のことについて考えましたか。

  • SELECT/*not important*/1/*really...*/FROM/*im serious*/users
  • SELECT%09FIELDS%09FROM%0dTABLE_NAME
  • WHERE username=CONCAT(CHAR(97),CHAR(100),CHAR(109),CHAR(105),CHAR(110))
  • SELECT passwd FROM users WHERE username=0x61646d696e

要約すると、HereBeDragonsです。

http://www.ihteam.net/papers/blind-sqli-regexp-attack.pdf

http://ferruh.mavituna.com/sql-injection-cheatsheet-oku/#HexbasedSamples

于 2012-04-25T11:24:30.730 に答える
1

SQLオブジェクトを使用したくない場合は、エントリを自分でサナタイズする必要があります。SQLの推奨フォーマットはわかりませんが、MySQLの場合は次のように機能します。SQLで動作するように変更しましたが、すべての可能なインジェクション攻撃をカバーしていることを保証できません。

public string sqlEscape(string VAL)
{
    if (VAL == null)
    {
        return null;
    }
    return "\"" + Regex.Replace(VAL, @"[\r\n\x00\x1a\\'""]", @"\$0") + "\"";
}

使用するには、次のようにします(CSV行がcsvという配列に格納されていると仮定します)。

string query = @"INSERT INTO Users (id, name, country) VALUES (" + sqlEscape(csv[0]) + ", " + sqlEscape(csv[1]) + ", " + sqlEscape(csv[2]) + ");";

誰かがこれを強化できるなら私に知らせてください!

于 2012-04-25T12:24:45.843 に答える