11

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

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

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

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

4

5 回答 5

14

如果您必须处理字符串,那么白名单是您最好的选择。首先,白名单应该很简单:与 /sortDirection比较时不区分大小写,你应该被设置。对于其他人,我更喜欢将已知列列入白名单,也许是通过传入数据的期望值并进行验证。但是在绝对紧要关头,您可以使用正则表达式限制(例如)强制它们都是严格的字母数字(在 az、AZ、0-9 范围内 - 如果需要,可能下划线) - 然后添加,即"asc""desc"Type[]

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

但是:已知列的严格白名单会好得多,方向的枚举也是如此。

于 2013-01-14T11:15:06.637 回答
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 ");
}

祝你好运。

于 2013-01-14T11:31:28.243 回答
0

您可以使用大型 CASE 语句来执行此操作,您可以在其中根据传递的列名称和方向进行切换。这里有一个答案。您将看到如下代码:

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
于 2013-01-14T11:15:56.283 回答
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 语句执行。

但是查询参数代替了单个值。您不能使用查询参数来替代动态表名、列名、值列表(例如,用于 IN() 谓词)、表达式或 SQL 关键字。

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

过滤是您去除任何会引起麻烦的字符的地方。如果您知道您的动态列名只能是字母数字字符,那么在 SQL 中使用之前对您的变量应用过滤器。否则,如果变量与 /^[A-Za-z0-9]*$/ 之类的正则表达式不匹配,则拒绝该变量

于 2013-01-14T11:22:38.897 回答
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
}
于 2013-01-14T11:39:22.573 回答