存储过程是否可以防止针对 PostgreSQL 数据库的 SQL 注入攻击?我做了一些研究,发现即使我们只使用存储过程,SQL Server、Oracle 和 MySQL 也不能安全地防止 SQL 注入。但是,这个问题在 PostgreSQL 中不存在。
PostgreSQL 核心中的存储过程实现是防止 SQL 注入攻击还是别的什么?或者即使我们只使用存储过程,PostgreSQL 也容易受到 SQL 注入的影响?如果是这样,请给我一个例子(例如书籍、网站、论文等)。
存储过程是否可以防止针对 PostgreSQL 数据库的 SQL 注入攻击?我做了一些研究,发现即使我们只使用存储过程,SQL Server、Oracle 和 MySQL 也不能安全地防止 SQL 注入。但是,这个问题在 PostgreSQL 中不存在。
PostgreSQL 核心中的存储过程实现是防止 SQL 注入攻击还是别的什么?或者即使我们只使用存储过程,PostgreSQL 也容易受到 SQL 注入的影响?如果是这样,请给我一个例子(例如书籍、网站、论文等)。
不,存储过程不会阻止 SQL 注入。这是一个不幸地允许 SQL 注入的存储过程的实际示例(来自某人在我工作的地方创建的内部应用程序):
这个 sql 服务器代码:
大致相当于postgres:
开发人员的想法是创建一个通用的搜索过程,但结果是 WHERE 子句可以包含用户想要的任何内容,从而允许从小Bobby Tables进行访问。
无论您使用 SQL 语句还是存储过程都无关紧要。重要的是您的 SQL 是使用参数还是连接字符串。参数防止SQL注入;串联的字符串允许 SQL 注入。
SQL 注入攻击是直接附加查询的不可信输入,允许用户有效地执行任意代码,如这本规范的 XKCD 漫画所示。
于是,我们得到了这样的情况:
存储过程通常可以很好地防御 SQL 注入攻击,因为从不解析传入的参数。
在存储过程中,在大多数数据库(和程序,不要忘记预编译查询算作存储过程)中,如下所示:
然后,当程序需要访问时,它会调用
foo(userInput)
并愉快地检索结果。存储过程并不是针对 SQL 注入的神奇防御,因为人们很可能编写糟糕的存储过程。但是,如果您了解 SQL 注入的工作原理,预编译的查询,无论是存储在数据库中还是程序中,都更难打开安全漏洞。
您可以阅读有关 SQL 注入的更多信息:
是的,在某种程度上。
单独的存储过程不会阻止 SQL 注入。
让我首先引用OWASP的 SQL 注入
您必须清理用户输入并且不要连接 SQL 语句,即使您使用的是存储过程。
Jeff Attwood 在“给我参数化 SQL,或者给我死亡”中解释了连接 sql 的后果
以下是每当我听到 SQL 注入时我脑海中浮现的有趣漫画, 我认为你明白了 :-)
看一下SQL Injection Prevention Cheat Sheet,预防方法被整齐地解释...
字符串连接是 SQL 注入的原因。使用参数化可以避免这种情况。
存储过程通过在连接时强制执行无效语法来增加额外的安全层,但如果在其中使用动态 SQL,则不会“更安全”。
因此,您上面的代码是由这些字符串的串联引起的
exec sp_GetUser '
x' AND 1=(SELECT COUNT(*) FROM Client); --
' , '
monkey
'
幸运的是,这给出了无效的语法
参数化它会给
这表示
@UserName
=x' AND 1=(SELECT COUNT(*) FROM Client); --
@Password
=monkey
现在,在上面的代码中你不会得到任何行,因为我假设你没有用户
x' AND 1=(SELECT COUNT(*) FROM Client); --
如果存储过程看起来像这样(使用串联的动态 SQL),那么您的参数化存储过程调用仍将允许 SQL 注入
因此,如所示,字符串连接是 SQL 注入的主要敌人
存储过程确实增加了封装、事务处理、减少权限等,但它们仍然可以被滥用于 SQL 注入。
您可以查看 Stack Overflow 以了解有关参数化的更多信息
“当用户输入编码不正确时,就会发生 SQL 注入攻击。通常,用户输入是用户通过查询发送的一些数据,即 , , , 或数组中的值
$_GET
。$_POST
但是$_COOKIE
,$_REQUEST
用户$_SERVER
输入也可以来自各种其他源,如套接字、远程网站、文件等。因此,您应该真正将除常量(如'foobar'
)之外的所有内容都视为用户输入。”我最近一直在深入研究这个主题,并想与其他人分享一些非常有趣的材料,从而使这篇文章对每个人都更加完整和有启发性。
来自 YouTube
来自维基百科
来自 OWASP
来自 PHP 手册
来自微软和甲骨文
堆栈溢出
SQL 注入扫描器
存储过程不会神奇地阻止 SQL 注入,但它们确实使阻止它变得容易得多。您所要做的就是如下所示(Postgres 示例):
而已!只有在通过字符串连接(即动态 SQL)形成查询时才会出现问题,即使在这些情况下,您也可以绑定!(取决于数据库。)
如何在动态查询中避免 SQL 注入:
第 1 步)问问自己是否真的需要动态查询。如果您只是为了设置输入而将字符串粘在一起,那么您可能做错了。(这个规则有例外——一个例外是报告对某些数据库的查询,如果你不强制它在每次执行时编译一个新查询,你可能会遇到性能问题。但是在你跳进去之前研究这个问题。 )
步骤 2) 研究为您的特定 RDBMS 设置变量的正确方法。例如,Oracle 允许您执行以下操作(引用他们的文档):
在这里,您仍然没有连接输入。您已安全绑定!万岁!
如果您的数据库不支持上述内容(希望它们都不是那么糟糕,但我不会感到惊讶) - 或者如果您仍然真的必须连接您的输入(例如在“有时”报告查询的情况下我在上面暗示过),那么你必须使用适当的转义函数。不要自己写。例如 postgres 提供了 quote_literal() 函数。所以你会运行:
这样,如果 in_name 是像 '[snip] 或 1=1' (“或 1=1” 部分意味着选择所有行,允许用户看到他不应该看到的薪水!),那么 quote_literal 会节省你的屁股制作结果字符串:
不会找到任何结果(除非您有一些名字非常奇怪的员工。)
这就是它的要点!现在让我为您提供 Oracle 专家 Tom Kyte 关于 SQL 注入主题的经典帖子的链接,让您明白这一点:Linky