在ORDER BY子句中阻止SQL注入

时间:2013-01-14 11:10:02

标签: c# sql-server-2008 sql-order-by sql-injection

在我们的数据库访问层中,我们有一些动态查询创建。例如,我们有以下方法来构建ORDER BY子句的一部分:

protected string BuildSortString(string sortColumn, string sortDirection, string defaultColumn)
{
    if (String.IsNullOrEmpty(sortColumn))
    {
        return defaultColumn;
    }

    return String.Format("{0} {1}", sortColumn, sortDirection);
}

问题是,sortColumnsortDirection都来自外部作为字符串,所以当然应该采取措施防止可能的注入攻击。有没有人知道如何做到这一点?

5 个答案:

答案 0 :(得分:11)

如果您 来处理字符串,那么白名单是最好的选择。首先,sortDirection应该对白名单非常简单:与"asc" / "desc"不区分大小写,您应该设置。对于其他人,我倾向于将已知列列入白名单,可能是通过传递预期的Type来获取数据并进行验证。但是在绝对压力下,你可以用正则表达式来限制(比方说)强制执行它们都是严格字母数字(在az,AZ,0-9范围内 - 如果需要可能是下划线) - 然后添加[],即

return string.Format("[{0}] {1}", sortColumn, sortDirection);

但是:严格的已知列的白名单会更好,就像方向的枚举一样。

答案 1 :(得分:1)

另一种解决方案,如果您可以更改方法以接受int而不是string参数。

protected string BuildSortString(int sortColumn, int sortDirection, string defaultColumn)
{
    if (String.IsNullOrEmpty(sortColumn))
    {
        return defaultColumn;
    }
//sortdirection 0-> "ASC" else "DESC"
//sorColumn 1 for your firstcolumn, 2 for your second column etc.
    return String.Format("{0} {1}", sortColumn, sortDirection==0? " ASC " : " DESC ");
}
祝你好运。

答案 2 :(得分:0)

您可以使用大型CASE语句执行此操作,您可以根据传递的列名称和方向进行切换。 There's an SO answer on that here。你将会看到如下代码:

SELECT
     *
FROM
     My_Table
WHERE
     Whatever = @something
ORDER BY
     CASE @sort_order
          WHEN 'ASC' THEN
               CASE @order_by
                    WHEN 'surname' THEN surname
                    WHEN 'forename' THEN forename
                    WHEN 'fullname' THEN fullname
                    ELSE surname
               END
          ELSE '1'
     END ASC,
     CASE @sort_order
          WHEN 'DESC' THEN
               CASE @order_by
                    WHEN 'surname' THEN surname
                    WHEN 'forename' THEN forename
                    WHEN 'fullname' THEN fullname
                    ELSE surname
               END
          ELSE '1'
     END DESC

答案 3 :(得分:0)

解决方案:cmd.Parameters或EscapedString,但我更喜欢cmd.Parameters(总是工作,你喜欢预期的例外)

示例:

cmd.CommandText = "SELECT UNIQUE_ID FROM userdetails WHERE USER_ID IN (?, ?)";
cmd.Parameters.Add("?ID1", OdbcType.VarChar, 250).Value = email1;
cmd.Parameters.Add("?ID2", OdbcType.VarChar, 250).Value = email2;
  

使用带参数的预准备语句有助于防御SQL   在大多数常见情况下进行注射,否则会进行插值   将不受信任的内容转换为字符串,然后将该字符串作为SQL执行   声明。

     

但是查询参数取代了单个值。你不能使用   查询参数作为动态表名称列的替代   name,值列表(例如,对于IN()谓词),表达式或SQL   关键字。

     

对于这些情况,您可以使用过滤或白名单等技术   因此,不要将不受信任的内容插入到SQL字符串中。

     

过滤是您删除任何可能导致的字符的地方   麻烦。如果您知道您的动态列名称应该只是   字母数字字符,然后在您的变量之前应用过滤器   在SQL中使用它。或者,如果变量与a不匹配,则拒绝变量   正则表达式,如/ ^ [A-Za-z0-9] * $ /

答案 4 :(得分:0)

你可以这样做:

public string BuildSortString(string sortColumn, SortDirection direction, string defaultColumn)
{
    string sortDirection = direction.ToString();

    if (String.IsNullOrEmpty(sortColumn))
    {
        return VerifyColumn(defaultColumn);
    }

    return String.Format("{0} {1}", VerifyColumn(sortColumn), sortDirection);
}

private string VerifyColumn(string column)
{
    switch (column) // fill this with a whitelist of accepted columns
    {
        case "some_column":
            return column;
    }

    return String.Empty; // the column must be invalid (do whatever you want here)
}

public enum SortDirection
{
    ASC, DESC
}