使用 OleDb 参数的目的是啥? [复制]
Posted
技术标签:
【中文标题】使用 OleDb 参数的目的是啥? [复制]【英文标题】:What is purpose of using OleDb Parameters? [duplicate]使用 OleDb 参数的目的是什么? [复制] 【发布时间】:2021-12-31 21:06:30 【问题描述】:我有使用 OLEDB 将数据输入数据库的代码。假设它看起来像这样
var commandText = $"INSERT into tableName
(columnName1, columnName2)
VALUES (value1, value2);"
var command = new OleDbCommand(commandText, connection);
command.ExecuteNonQuery();
建议使用OLEDB参数,类似这样
var commandText = $"INSERT into tableName
([columnName1], [columnName2])
VALUES (?, ?);"
var command = new OleDbCommand(commandText, connection);
command.Parameters.Add(new OleDbParameter(columnName1, value1));
command.Parameters.Add(new OleDbParameter(columnName2, value2));
command.ExecuteNonQuery();
在这里使用参数有什么好处?
如果之前验证过这些值,真的会提高安全性吗?
【问题讨论】:
Does it really improve security if the values are validated before?
- 是。因为总会有一个比你的验证更聪明的攻击者(白名单除外)。您还应该真正尝试重构您的软件,这样您就不必以这种方式注入表/列名。参数化语句还可能有助于提高性能并防止无数的语法错误。 (总是期望你的用户是愚蠢的,而你的攻击者是聪明的)
简而言之,是的。连接到 SQL Server,将value
设置为1, 2); DROP DATABASE MyDb; --
,你就遇到了经典的 SQL 注入攻击,有很多方法可以重写它并逃避检测。更重要的是,像NULL
这样的值、带引号的字符串和日期/时间文字在插入值时都需要特别注意。值被“验证”的想法很好,但参数构成了注入攻击的绝对障碍,而验证则没有。
假设您有以下查询:string query = "SELECT Id FROM Users WHERE Name = '" + userName + "' AND password = '" + password + "'";
,然后有人输入用户名值' OR Name = 'SysAdmin' ; -- comment
。被执行的查询将被组合成这样:"SELECT Id FROM Users WHERE Name = '' OR Name = 'SysAdmin' ; -- comment' AND password = 'somevalue';
。就这样,用户以管理员身份登录!或者更糟糕的是,他们的“用户名”是' ; DROP TABLE User; -- comment
,而您刚刚丢失了用户表。已验证,当然。确信自己没有错过什么?
some fundamental infos about SQL Injection attacks
这不仅仅是安全性。参数是强类型的二进制值。您避免了代码中的类型转换和本地化问题(什么日期格式?什么小数分隔符?)和节省空间。使用参数允许重用执行计划,从而显着提高性能,尤其是对于简单频繁执行的查询
【参考方案1】:
使用此代码,再多的参数也无济于事。
连接表名和列名的事实使您的查询容易受到 SQL 注入攻击,这是使用参数的主要(但不仅是)原因。
SQL 注入的工作方式是将发送到数据库的部分字符串替换为 sql 代码。参数可以防止这种情况发生,因为数据库将它们视为数据的占位符,这意味着它不会运行任何通过它们传递的 sql 代码。 但是,由于您的表名和列名也是 c# 变量,因此可以将它们替换为数据库将尝试运行的 SQL 代码。
假设如下代码:
var tableName = "table (Col1) VALUES (null);DROP TABLE table;--";
// declare and populate columnName1, columnName2 with whatever values you want here, even just nulls
var commandText = $"INSERT into tableName
([columnName1], [columnName2])
VALUES (?, ?);"
// run SQL command here
这将在table
中插入一条记录,然后从数据库中删除该表。
欲了解更多信息,请阅读我题为Back to basics: SQL Injection的博文
【讨论】:
【参考方案2】:事实上,是的。我们都会犯错,而参数对象所增加的额外安全性就像第二双眼睛。 此外,如果您始终使用参数对象,则在后续引入错误的风险会更小。
【讨论】:
不是这样的。再多的手动检查和转义也无法阻止使用参数消除的 SQL 注入问题、类型转换或本地化错误。参数也通过使用缓存的执行计划来提高性能,而使用动态 SQL 根本无法做到这一点。当您传递DateTime
参数值时,您传递的是明确的二进制 DateTime
值,而不是本地化字符串。
@PanagiotisKanavos 谢谢。你说的比我好得多,但重点仍然是正确的。恕我直言,永远不要使用没有参数对象的 SQL。以上是关于使用 OleDb 参数的目的是啥? [复制]的主要内容,如果未能解决你的问题,请参考以下文章