5

我有一个项目(私人,ASP.net 网站,密码保护 https),其中一个要求是用户能够输入将直接查询数据库的 Sql 查询。我需要能够允许这些查询,同时防止它们对数据库本身造成损害,以及访问或更新他们不应该能够访问/更新的数据。

我提出了以下实施规则:

  1. 使用只有Select Table/View 和 Update Table 权限的 db 用户(因此任何其他命令,如 drop/alter/truncate/insert/delete 都不会运行)。
  2. 验证语句是否以“Select”或“Update”开头
  3. 验证(使用正则表达式)语句中没有没有被单引号、空格和字母包围的分号实例。(这里的想法是,他们可以包含第二个查询的唯一方法是用不属于输入字符串的分号结束第一个查询)。
  4. 验证(使用正则表达式)用户有权访问正在查询/更新的表,包括在连接中等。这包括任何子查询。(实现这一点的部分方法是用户将使用一组实际上并不存在于数据库中的表名,部分查询解析将在正确的对应表名中替换为查询) .

我错过了什么吗?

目标是用户能够以他们认为合适的任何方式查询/更新他们有权访问的表,并防止任何意外或恶意尝试损坏数据库。(并且由于要求是用户生成 sql,因此我无法使用我知道的任何内置工具对查询进行参数化或清理)。

4

15 回答 15

16

这是一个坏主意,不仅仅是从注射预防的角度来看。对于一个不知道更好的用户来说,意外运行一个会占用所有数据库资源(内存/cpu)的查询真的很容易,从而有效地导致拒绝服务攻击。

如果您必须允许这样做,最好为这些查询保留一个完全独立的服务器,并使用复制使其非常接近生产系统的精确镜像。当然,这不适用于您的 UPDATE 要求。

但我想再说一遍:这行不通。如果用户可以运行即席查询,您将无法保护您的数据库。

于 2009-01-14T19:20:31.677 回答
4

这个东西怎么样,想象一下 select 是一个 EXEC

select convert(varchar(50),0x64726F70207461626C652061)
于 2009-01-14T19:09:53.477 回答
4

我的直觉反应是,您应该专注于尽可能严格地设置帐户权限和授权。彻底查看您的 RDBMS 安全文档,可能有一些您不熟悉的特性会证明是有用的(例如,我相信 Oracle 的虚拟专用数据库可能在这种情况下有用)。

特别是,您的想法是“验证(使用正则表达式)用户有权访问正在查询/更新的表,包括在联接中,等等。” 听起来您会尝试重新实现已内置于数据库中的安全功能。

于 2009-01-14T19:34:47.140 回答
3

您缺少的是攻击者在您的应用程序中发现漏洞的独创性。

我几乎可以向你保证,如果你允许的话,你将无法关闭所有的洞。数据库引擎中甚至可能存在您不知道的错误,但它们确实允许您认为安全的 SQL 语句在您的系统中造成严重破坏。

简而言之:这是一个非常糟糕的主意!

于 2009-01-14T19:37:09.833 回答
3

好吧,你已经有足够多的人告诉你“不要这样做”,所以如果他们无法劝阻你,这里有一些想法:

包括好的,不要试图排除坏的
(我认为正确的术语是Whitelisting vs Blacklisting)也就是说,我的意思是不要寻找邪恶或无效的东西来扔掉(它可以写的方式太多了或伪装),而是寻找有效的东西来包含并扔掉其他所有东西。

您已经在另一条评论中提到您正在寻找用户友好的表名列表,并替换实际的模式表名。这就是我要说的——如果您要这样做,那么也可以使用字段名称。

不过,我仍然倾向于某种图形用户界面:选择要在此处查看的表,选择要在此处查看的字段,使用一些下拉菜单来构建 where 子句等。虽然很痛苦,但可能仍然更容易。

于 2009-01-14T20:11:52.650 回答
2

正如其他人所指出的,让最终用户这样做并不是一个好主意。我怀疑这个需求并不是用户真的需要 ad-hoc SQL,而是一种以最初没有预见到的方式获取和更新数据的方法。要允许查询,请按照 Joel 的建议进行操作并保留“只读”数据库,但使用 Microsoft Reporting Services 或 Data Dynamics Active 报告等报告应用程序来允许用户设计和运行临时报告。我相信两者都有办法向用户展示“他们的”数据的过滤视图。

对于更新,它更棘手 - 我不知道现有的工具可以做到这一点。一种选择可能是设计您的应用程序,以便开发人员可以快速编写插件来公开用于更新数据的新表单。该插件需要公开一个 UI 表单、用于检查当前用户是否可以执行它的代码以及用于执行它的代码。您的应用程序将加载所有插件并公开用户有权访问的表单。

于 2009-01-14T19:57:32.773 回答
2

事件看似安全的技术,如动态 LINQ,对代码注入问题并不安全,您正在谈论提供低级访问。

无论您多么努力地清理查询和调整权限,仍然可能通过发送一些 CPU 密集型查询来冻结您的数据库。

因此,“保护选项”之一是显示一个消息框,告诉所有访问受限对象或导致不良副作用的查询都将记录在用户帐户中并立即报告给管理员

另一种选择 - 只是尝试寻找更好的选择(即,如果您真的需要处理和更新数据,为什么不公开 API 以安全地执行此操作?)

于 2009-01-15T05:01:38.603 回答
1

一个(可能是矫枉过正)选项可以使用编译器来简化 SQL 语言。像使用 JavaCC 和修改后的 SQL 语法,只允许 SELECT 语句,然后你可能会收到查询,编译它,如果它编译,你可以运行它。

对于 C#,我知道Irony,但从未使用过它。

于 2009-01-14T19:11:33.507 回答
1

使用更新语句可以造成巨大的损失。

我有一个类似的项目,我们的解决方案是引导用户完成一个非常烦人的向导,让他们做出选择,但查询本身是由应用程序代码在幕后构建的。创建起来非常费力,但至少我们控制了最终执行的代码。

于 2009-01-14T19:30:57.007 回答
1

问题是,你信任你的用户吗?如果您的用户必须登录系统,而您使用的是 HTTPS 并采取了预防 XSS 攻击的措施,那么 SQL 注入是一个较小的问题。如果您信任合法用户,则在受限帐户下运行查询就足够了。多年来,我一直在网络上运行 MyLittleAdmin,但还没有遇到任何问题。

如果您在受适当限制的 SQL 帐户下运行,则 select convert(varchar(50),0x64726F70207461626C652061) 不会走得太远,您可以通过在数据库请求上设置短超时来防御资源占用查询。人们仍然可以进行不正确的更新,但是这又回到了您是否信任您的用户?

将任何数据库附加到 Web 时,您总是要承担受管理的风险,但这就是备份的用途。

于 2009-01-14T19:42:31.710 回答
0

如果他们不必执行真正高级的查询,您可以提供一个只允许某些选择的 ui,例如带有“更新、删除、选择”的下拉列表,然后下一个 ddl 将自动填充可用表的列表等。 . 类似于 sql management studio 中的查询生成器。

然后在您的服务器端代码中,您会将这些 ui 元素组转换为 sql 语句并使用参数化查询来阻止恶意内容

于 2009-01-14T19:15:57.663 回答
0

这是一个非常糟糕的做法。我会创建一些存储过程来处理您想做的所有事情,甚至是更高级的查询。将它们呈现给用户,让他们选择他们想要的,然后传递你的参数。

我上面的答案也非常好。

于 2009-01-14T19:33:27.487 回答
0

尽管我同意 Joel Coehoorn 和 SQLMenace 的观点,但我们中的一些人确实有“要求”。与其让他们发送即席查询,不如创建一个可视化查询构建器,就像在 asp.net 上的 MS 示例应用程序中找到的那样,或者试试这个链接

我不反对乔尔提出的观点。他是对的。让用户(记住我们在这里谈论的是用户,他们可能不太关心你想要强制执行什么)抛出查询就像一个没有“业务逻辑层”的应用程序,更不用说当某些结果不匹配时要回答的其他问题其他配套申请结果。

于 2009-01-14T19:50:01.587 回答
0

这是另一个例子

黑客不需要知道真实的表名,他/她可以像这样运行未记录的过程

sp_msforeachtable 'print ''?''' 

只是代替打印,它将被丢弃

于 2009-01-14T20:43:42.273 回答
0

很多答案说这是一个坏主意,但有时这就是要求所坚持的。不过,在“如果你仍然必须这样做”的建议中,我没有发现一个问题:确保任何更新语句都包含 WHERE 子句。跑起来太容易了

UPDATE ImportantTable
SET VitalColumn = NULL

错过了重要的

WHERE UserID = @USER_NAME

如果整个表都需要更新,那么添加很容易

WHERE 1 = 1

要求 where 子句不会阻止恶意用户做坏事,但它应该减少意外的整个表更改。

于 2013-01-15T17:31:25.137 回答