In our DB access layer we have some dynamic query creation. For instance, we have the following method for building a part of an ORDER BY
clause:
protected string BuildSortString(string sortColumn, string sortDirection, string defaultColumn)
{
if (String.IsNullOrEmpty(sortColumn))
{
return defaultColumn;
}
return String.Format("{0} {1}", sortColumn, sortDirection);
}
The problem is, sortColumn
and sortDirection
both come from outside as strings, so of course something should be done to prevent possible injection attacks. Does anybody have any idea how this can be done?
If you have to deal in strings, then white-listing is your best bet. Firstly, sortDirection
should be pretty trivial to white-list: a case-insensitive compare to "asc"
/ "desc"
and you should be set. For the others, my preference would be to white-list to known columns, perhaps by passing in the expected Type
for the data and validating. But at an absolute pinch, you could restrict with regex to (say) enforce they are all strictly alpha-numeric (in the a-z, A-Z, 0-9 range - maybe underscore if needed) - and then add []
, i.e.
return string.Format("[{0}] {1}", sortColumn, sortDirection);
But: strict white-list of known columns would be much better, as would an enum for the direction.
Another solution if you can change your method to accept int
instead of string
parameters.
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 ");
}
Good luck.
You can do this using a large CASE statement where you switch based off the passed column name and direction. There's an SO answer on that here. You're going to be looking at code like:
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
Solution: cmd.Parameters or EscapedString, but I prefer cmd.Parameters (always work and you enjoy the Exceptions expected)
example:
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;
Using prepared statements with parameters helps to defend against SQL injection in most common cases, when you would otherwise interpolate untrusted content into a string and then execute the string as an SQL statement.
But a query parameter takes the place of a single value. You can't use a query parameter as a substitute for a dynamic table name, column name, list of values (e.g. for an IN() predicate), expressions, or SQL keywords.
For those cases, you can use techniques like filtering or whitelisting so you don't interpolate untrusted content into your SQL strings.
Filtering is where you strip out any characters that would cause trouble. If you know your dynamic column name should only be alphanumeric characters, then apply a filter to your variable before using it in SQL. Or else just reject a variable if it doesn't match a regular expression like /^[A-Za-z0-9]*$/
You could do something like this:
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
}
来源:https://stackoverflow.com/questions/14317341/prevent-sql-injection-in-order-by-clause