我知道如何从C#执行查询,但我想提供一个下拉列表,人们可以在其中编写查询,然后执行并填充列表。
问题是我想以任何方式禁止所有修改数据库的查询。我还没有找到办法做到这一点,我用谷歌做到了最好。
我能想到的解决方案是我将扫描查询INSERT,DELETE,UPDATE并且只允许SELECT语句。但是,我希望能够允许用户也可以调用存储过程。这意味着我需要获取存储过程的主体并在执行之前对其进行扫描。我如何下载存储过程?
如果有人知道只执行只读查询的方法请分享!我有感觉扫描文本INSERT,DELETE,UPDATE不会阻止SQL注入。
答案 0 :(得分:12)
执行此操作的最简单方法可能是将此作业卸载到数据库。只需确保将运行查询的数据库用户具有只读 的读访问权限。然后,执行SELECT
以外任何操作的任何查询都将失败,您可以将该失败报告给用户。
如果你不采用这种方式,复杂性就会变得非常庞大,因为你基本上必须准备解析一个任意的SQL语句,如果你允许的话,更不用说SQL语句的任意序列存储过程将被运行。
即便如此,请注意确保您不会通过查询泄露敏感数据。如果您不小心,直接从站点用户输入查询可能会很危险。即使你是这样,允许这些查询除了专门构建的沙盒数据库之外的任何东西都是“哎呀,我不小心改变了用户的权限”而不是成为安全噩梦。
另一种选择是编写“查询创建者”页面,用户可以在其中选择他们想要查看的表格和列。然后,您可以a)仅显示适合给定用户的表和列(可能基于用户角色等)和b)自己生成SQL,最好使用参数化查询。
更新:正如Yahia所指出的,如果用户具有执行权限(以便他们可以执行存储过程),那么过程本身的权限就会受到尊重。鉴于此,不允许任意存储的proc执行可能更好,而是为用户提供已知安全的过程列表。但这可能很难维护并且容易出错,因此完全不允许存储过程可能是最好的。
答案 1 :(得分:4)
如何在仅具有select(只读)权限的数据库服务器上创建用户帐户?
答案 2 :(得分:2)
也许你可以设置一个对数据库具有只读访问权限的SQL用户并使用该用户发出命令?然后你可以在/它们发生时捕获错误。
在我看来,尝试解析查询以确定它是否修改数据库会非常困难且容易出错。
答案 3 :(得分:1)
您无法可靠地解析SQL。
使用权限
答案 4 :(得分:1)
最好是不允许用户输入SQL并仅使用准备/参数化查询...
防止这种情况的另一个最佳方法是使用具有纯读取权限的受限用户 以上两个可以合并......
<强>提防强>
要执行存储过程,用户必须具有执行权限...如果存储过程修改数据,那么即使使用受限用户也不会出现错误消息,因为修改权限被授予存储过程!
如果您绝对必须允许用户输入SQL并且无法限制登录,那么您需要使用SQL解析器 - 例如this ...
关于如何下载存储过程的主体 - 这取决于您使用的数据库(SQL Server,Oracle等)。
修改强>
另一个选项是所谓的“数据库防火墙” - 你连接而不是直接连接数据库到防火墙...在防火墙中你配置了一些东西,比如基于时间的限制(当特定的用户/声明是/艺术不是允许),基于SQL的语句(允许...),基于数量的限制(如你可以获得100条记录,但无法下载整个表/ DB ......)等。
有商业和开源数据库防火墙 - 虽然这些本质上非常依赖于您使用的数据库等。
实例:
答案 5 :(得分:0)
不要忘记比INSERT,UPDATE和DELETE更糟糕的事情。就像TRUNCATE ......这是一些不好的东西。
答案 6 :(得分:0)
我认为SQL Trigger
是您想要做的最佳方式。
答案 7 :(得分:0)
您的第一步应该是为这个特定任务创建一个DB用户,只需要所需的权限(基本上只有SELECT),并且有权只查看您需要他们看到的表(因此他们不能SELECT sys表或你的用户表。)
更一般地说,让用户直接在数据库上执行代码似乎是一个坏主意。例如,即使您保护它免受数据修改,它们仍然可以进行丑陋的连接以使您的数据库运行缓慢。
也许您使用UI编程的语言,您可以尝试在线查找允许对数据库进行过滤的自定义控件。 Google它......
答案 8 :(得分:0)
这不完美但可能是你想要的,这允许关键字出现,如果它是一个更大的字母数字字符串的一部分:
public static bool ValidateQuery(string query)
{
return !ValidateRegex("delete", query) && !ValidateRegex("exec", query) && !ValidateRegex("insert", query) && !ValidateRegex("alter", query) &&
!ValidateRegex("create", query) && !ValidateRegex("drop", query) && !ValidateRegex("truncate", query);
}
public static bool ValidateRegex(string term, string query)
{
// this regex finds all keywords {0} that are not leading or trailing by alphanumeric
return new Regex(string.Format("([^0-9a-z]{0}[^0-9a-z])|(^{0}[^0-9a-z])", term), RegexOptions.IgnoreCase).IsMatch(query);
}
你可以在这里看到它是如何运作的:regexstorm
请参阅正则表达式备忘单:cheatsheet1,cheatsheet2
请注意这并不完美,因为它可能会阻止使用其中一个关键字作为引用的查询,但是如果您编写查询并且只是一个预防措施,那么这可能会起作用。
您也可以采用不同的方法,尝试查询,如果它影响数据库,请执行回滚:
public static bool IsDbAffected(string query, string conn, List<SqlParameter> parameters = null)
{
var response = false;
using (var sqlConnection = new SqlConnection(conn))
{
sqlConnection.Open();
using (var transaction = sqlConnection.BeginTransaction("Test Transaction"))
using (var command = new SqlCommand(query, sqlConnection, transaction))
{
command.Connection = sqlConnection;
command.CommandType = CommandType.Text;
command.CommandText = query;
if (parameters != null)
command.Parameters.AddRange(parameters.ToArray());
// ExecuteNonQuery() does not return data at all: only the number of rows affected by an insert, update, or delete.
if (command.ExecuteNonQuery() > 0)
{
transaction.Rollback("Test Transaction");
response = true;
}
transaction.Dispose();
command.Dispose();
}
}
return response;
}
你也可以将两者结合起来。