C#用定义的值替换查询中的参数

时间:2016-04-19 14:14:24

标签: c# loops replace parameters

string[] theParms = ['parm1', 'parm2'];
string theQuery = "SELECT something, somethingAgain " + 
                  "FROM aDBTable " +
                  "WHERE something = '{?}'" +
                  "AND something <> '{?}'";

我需要将{?}替换为 theParms 中定义的参数。

C#中是否存在某种类型的循环,我可以使用它来遍历字符串并将每个找到的{?}替换为相应的parm值?< / p>

这样的事情:

第一循环:

SELECT something, somethingAgain 
FROM aDBTable 
WHERE something = 'parm1' AND something <> '{?}'

第二次循环:

SELECT something, somethingAgain 
FROM aDBTable 
WHERE something = 'parm1' AND something <> 'parm2'

是否有某种类型的 REGEX 或通用框架功能可以执行上述操作?

sql注入检查

bool injectionCheckin = new injectionCheck().inCheck(theFinalQuery);

public class injectionCheck
{
    public bool inCheck(string queryString)
    {
        var badWords = new[] {
            "EXEC", "EXECUTE", ";", "-", "*", "--", "@",
            "UNION", "DROP","DELETE", "UPDATE", "INSERT",
            "MASTER", "TABLE", "XP_CMDSHELL", "CREATE",
            "XP_FIXEDDRIVES", "SYSCOLUMNS", "SYSOBJECTS",
            "BC_HOME_ADDRESS1", "BC_HOME_ADDRESS2", "BC_HOME_CITY", "BC_HOME_COUNTY", "BC_HOME_POSTAL", "BC_MAIL_ADDRESS1",
            "BC_MAIL_ADDRESS2", "BC_MAIL_CITY", "BC_MAIL_COUNTY", "BC_MAIL_POSTAL", "BC_MAIL_STATE", "FLSA_STATUS", "GRADE",
            "GRADE_ENTRY_DT", "HIGHEST_EDUC_LVL", "LAST_INCREASE_DT", "BC_SALP_DESCR", "BC_SALP_DESCRSHORT", "SAL_ADMIN_PLAN"
        };
        string pattern = "(?<!\\w)(" + Regex.Escape(badWords[0]);

        foreach (var key in badWords.Skip(1))
        {
            pattern += "|" + Regex.Escape(key);
        }

        pattern += ")(?!\\w)";

        dynamic _tmpCount = Regex.Matches(queryString, pattern, RegexOptions.IgnoreCase).Count;

        if (_tmpCount >= 1)
            return true;
        else
            return false;
    }
}

6 个答案:

答案 0 :(得分:2)

为什么不使用String.Format

string[] theParms = new string[] { "parm1", "parm2" };
string theQuery = @"SELECT something, somethingAgain 
                    FROM aDBTable 
                    WHERE something = '{0}'
                    AND something <> '{1}'";
var res = string.Format(theQuery, theParms);

结果:

SELECT something, somethingAgain 
       FROM aDBTable 
       WHERE something = 'parm1'
       AND something <> 'parm2'

答案 1 :(得分:2)

始终按parameterized queries创建Sql命令:

using (SqlConnection conn = new SqlConnection(DatabaseConnectionString))
using (SqlCommand cmd = conn.CreateCommand())
{
    var @params = new Dictionary<string, object>{
        { "something", myValue },
        { "somethingDifferent", anotherValue },
    };

    cmd.CommandText = "SELECT something, somethingAgain " + 
              "FROM aDBTable " +
              "WHERE something = @something'" +
              "AND something <> @somethingDifferent'";
    foreach (KeyValuePair<string, object> item in values)
    {
        cmd.Parameters.AddWithValue("@" + item.Key, item.Value);
    }

    DataTable table = new DataTable();
    using (var reader = cmd.ExecuteReader())
        {
            table.Load(reader);
            return table;
        }
    }
}

这可以防止所有类型的SqlInjection,并且你不会因为你的坏名单而进行任何奇怪的检查,这是非常混乱而且并没有真正阻止你,你可以通过一些转义来轻松绕过列表。特别是:当你已经准备就绪的方法完全符合你的要求时,你为什么要编写自己的验证呢?

答案 2 :(得分:1)

如果你想在任何一种情况下都这样做,你可以按照以下方式进行循环。

string theQuery = String.Format( "SELECT something, somethingAgain " + 
                                 "FROM aDBTable " +
                                 "WHERE something = '{0}'" +
                                 "AND something <> '{1}'",
                                 theParams[0], theParams[1] );

答案 3 :(得分:1)

好的,为了避免注射以及所有这些,你为什么不这样做:

string[] theParms = // initialization
string theQuery = // initialization

SqlCommand cmd = new SqlCommand(/* enter connection string */, theQuery)

for(int i = 0; i < theParams.Length; i++)
{
    int index = cmd.Text.IndexOf("{?}");
    if(index > -1)
    {
        string pName = string.Format("@p{0}", i);
        cmd.Text = cmd.Text.Remove(index, 3).Insert(index, pName);
        cmd.Parameters.Add(new SqlParameter() { Name = pName, Value = theParms[i] });
    }
}

这应该完全避免任何手动注入检查...至少如果你不能预先编译查询并且必须在运行时加载它。否则只需适当地制定SqlCommand的文本,你就不需要循环或任何东西。只是一个简单的初始化:

SqlCommand cmd = new SqlCommand(/* enter connection string */, "SELECT something, somethingAgain FROM aDBTable WHERE something = @p0 AND something <> @p1");
cmd.Parameters.Add(new SqlParameter() { Name = "@p0", Value = theParms[0] });
cmd.Parameters.Add(new SqlParameter() { Name = "@p1", Value = theParms[1] });

答案 4 :(得分:0)

您可以使用IndexOf和子字符串查找每个实例

for(int i = 0; i < theParms.GetLength(0); i++)
{
    string[] tempStrings = new string[]{ theQuery.Substring(0,theQuery.IndexOf("{?}") - 1),
    theQuery.Substring(theQuery.IndexOf("{?}"), 3),
    theQuery.Substring(theQuery.IndexOf("{?}") + 4) }
    tempStrings[1] = tempStrings[1].Replace("{?}", theParms[i]);
    theQuery = String.Join("", tempStrings);
}

虽然看到你之后检查注射,但使用String.Format

肯定要好得多

答案 5 :(得分:-1)

你不必自己处理它。相反,ADO.NET允许您定义参数并设置其值。请参阅此处的示例。MSDN