在ORDER BY子句中阻止SQL注入

在我们的数据库访问层中,我们有一些动态查询创建。 例如,我们有以下方法来构建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都来自外部作为字符串,所以当然应该采取措施来防止可能的注入攻击。 有没有人知道如何做到这一点?

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

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

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

另一种解决方案,如果您可以将方法更改为接受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 "); } 

祝好运。

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

 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 

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

例:

 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中使用它之前应用filter。 或者只是拒绝一个变量,如果它与正则表达式不匹配,如/ ^ [A-Za-z0-9] * $ /

你可以这样做:

 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 }