存储过程有助于消除SQL注入吗?相比普通的SQL语句,存储过程在应用程序中有哪些好处?

11

我对SQL世界还比较陌生,以下是我的问题:

  • 存储过程相对于普通SQL语句在应用程序中有哪些好处?
  • 存储过程有助于消除SQL注入吗?
  • 在Microsoft SQL Server中称为存储过程,在Oracle、MySQL、DB2等数据库中呢?

感谢您的解答。

5个回答

8

存储过程只有在以参数化方式调用它们时才能直接防止 SQL 注入。如果您仍然在应用程序中使用字符串来表示存储过程名称,并将用户输入的参数连接到该字符串中,那么仍会出现问题。

但是,当专门使用存储过程时,您可以通过禁用 EXEC 命令以外的所有权限来增加一些额外的保护。此外,参数化查询/预处理语句通常由服务器缓存,因此在几乎所有方面与存储过程类似。

尽管如此,对于大型企业而言,存储过程具有两个重要优势:

  • 它们允许您为数据库定义应用程序接口,以便系统可以在多个应用程序之间共享,而无需在这些应用程序中复制逻辑。
  • 它们将 SQL 代码移动到数据库中,您可以轻松地让经验丰富的 DBA 对其进行调整、更新和维护,而不是让应用程序开发人员来处理他们可能并不熟悉的数据库代码。

当然,这些优点也不是没有代价的:

  • 更难跟踪源代码控制中的更改
  • 数据库代码与使用它的代码相隔甚远
  • 用于管理许多存储过程的开发人员工具不太理想(如果您曾经在管理工作室中打开存储过程文件夹,发现一个数据库有200个存储过程,那么您就知道我在这里说什么了)。

虽然您的优势在中大型企业确实存在,因为那里有数据库管理员,但对于像我这样以清理别人代码为生的人来说,它会产生噩梦般的工作。性能优势根本不值得在小企业中冒滥用风险。 - Spencer Ruport

6

在使用存储过程时,一些我认为的好处:

  • 存储过程将查询代码封装在服务器端,而不是应用程序内部。这样可以在不重新编译应用程序的情况下更改查询。
  • 存储过程可用于更明确定义的应用程序安全性。您可以拒绝所有基本表的权限,在处理过程上仅授予执行权限。这使您需要管理的安全性足迹更小。
  • 存储过程是编译代码。在最新版本的MSSQL中,服务器在存储执行计划方面做得更好 - 所以这不像以前那么重要,但仍需考虑。
  • 只有正确使用时,存储过程才能消除SQL注入风险。确保在存储过程中正确使用参数 - 只是在其中执行连接的动态SQL的存储过程对任何人都没有好处。

1
我不同意Bouma的观点。ORM在软件开发中有其应用场景,存储过程也是如此。完全否定其中之一似乎是一个错误的立场。原帖作者说他“对SQL不熟悉” - 因此他应该学习关于存储过程和ORM的所有知识 - 这样他可以为他所参与的每个项目做出明智的决策,以确定哪种方法适合当前情况。 - Scott Ivey
1
回复:sprocs are bad article: RUBBISH 1)所有的SQL都是脆弱的——无论它在哪里,模型的更改都需要更新它(包括应用程序代码) 2)洋葱防御,安全性分层。 3)性能——给我展示一个在您选择的语言中执行速度比FOR循环慢的游标,我会向您展示一条急需调整的SQL语句。 - OMG Ponies
@rexam - 说得好。当我说“不良立场”时,我不得不控制自己的措辞... - Scott Ivey

2
对于大部分情况来说,使用存储过程会比较不容易受到SQL注入的攻击。尽管有时候你需要向存储过程传递一些数据,这些数据需要在存储过程内使用动态SQL语句,这样就回到了原点。从这个意义上讲,我认为它们并没有比在支持参数化查询的编程语言中使用参数查询更有优势。
个人而言,我不喜欢存储过程。在两个不同的地方有代码是很让人头疼的,它会让部署变得复杂。然而,我也不赞成在代码里面添加大量的SQL语句,因为这会带来另一系列的问题。
我推荐使用以下两种方式之一实现DAL层:
  1. 我的最爱,使用对象关系管理系统(ORM)。 我一直在使用nHibernate,我非常喜欢它。 学习曲线很陡峭,但在我看来,它绝对是值得的。
  2. 某种机制来将所有的SQL代码放在一个地方。 可以是某种查询库,也可以是一组极其结构化的类, 用于设计SQL。我不建议使用这种方式, 因为它基本上像是构建自己的ORM,而可能你没有时间正确地完成它。
忘记存储过程。使用ORM。

4
最好使用一个使用存储过程的ORM。 - Scott Ivey
@Scott:不知道那个存在,但那也是一个很好的选择。 - Spencer Ruport

0
存储过程允许您将 SQL 代码存储在应用程序之外的位置。这使您能够:
  • 更改 SQL 代码而无需重新编译/重新分发应用程序
  • 多个应用程序使用相同的存储过程来访问相同的数据。
  • 限制用户直接读取/写入数据库中的表的访问权限。
  • 从开发角度来看,它还允许 DBA/数据库程序员在不必经过应用程序代码的情况下处理 SQL 代码(基本上是责任分离)。

存储过程是否可以防止注入攻击?大部分情况下是可以的。在 SQL Server 中,您可以创建不受此影响的存储过程,主要是通过使用 sp_executesql。现在,这并不意味着 sp_executesql 是一个安全漏洞,只是意味着在使用它时需要更加谨慎。

这也并不意味着存储过程是防止注入攻击的唯一方法。您可以使用参数化 SQL 来完成相同的任务以防止 SQL 注入。

我同意其他人的看法,存储过程可能会很麻烦,但它们也有优点。在我工作的地方,我们可能有20个不同的生产数据库,出于各种原因(别问为什么)。我只处理其中的三个子集,我和我的队友非常了解这三个子集。存储过程如何帮助我们?当人们需要从这些数据库中获取信息时,他们来找我们,我们可以为他们获取信息。我们不必花费数小时来解释模式和哪些数据被去规范化。这是一层抽象,使我们能够针对我们所知道的数据库编写最有效的代码。如果这对你不适用,那么存储过程可能不是最好的选择,但在某些情况下,它们可以增加很多价值。


修改SQL代码而无需重新编译/重新分发应用程序。当然需要编译。仅仅因为您没有调用make或ant或其他工具,不意味着它没有被编译。更重要的是:当然您必须部署它,否则您是在建议直接在生产数据库中更改代码吗? - Jens Schauder
不,你说得对,我的意思是重新编译应用程序代码(如C#或Java)。在某些情况下确实需要部署它,但如果必要,您可以从服务器中获取SQL代码并执行更新,而不像桌面应用程序那样需要重新部署到数百台机器。 - kemiller2002

0
存储过程(不使用动态SQL的存储过程)可以使整个应用程序更加安全的一种方法是,您现在可以在存储过程级别而不是表级别设置权限。如果您以这种方式进行所有数据访问(并禁止动态SQL!),这意味着用户无论如何都不能对数据库执行任何不在存储过程中的操作。开发人员总是想说他们的应用程序代码可以防止外部威胁,但他们似乎忘记了内部威胁通常更为严重,并且通过允许在表级别设置权限,他们处于任何可以找到直接查询数据库的用户的控制之下(这也是为什么在大型企业中,只有两三个人拥有生产环境权限,限制了谁可以窃取信息的原因之一)。
例如,任何使用除存储过程以外的东西的金融系统都完全面向内部欺诈,这违反了应该防止欺诈的内部控制,并且不会通过良好的审计。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接