存储过程可以防止对PostgreSQL数据库进行SQL注入攻击吗?我进行了一些研究,发现即使仅使用存储过程,SQL Server,Oracle和MySQL也不会对SQL注入造成威胁。但是,PostgreSQL中不存在此问题。

PostgreSQL核心中的存储过程实现是防止SQL注入攻击还是其他?还是即使我们仅使用存储过程,PostgreSQL也容易受到SQL注入的影响吗?如果是这样,请给我看一个例子(例如书籍,网站,纸张等)。

评论

奇怪的是,这里的最高答案主要是与SQL Server有关的OT,而问题与Postgres有关。这是Postgres的相关答案:dba.stackexchange.com/questions/49699/…。还有其他几个,请尝试搜索:dba.stackexchange.com/…

@ErwinBrandstetter最初的问题没有(由OP)用postgres标记,并且-仍然-提到了其他几个DBMS。我想这就是将各种答案集中在其他DBMS上的原因。我建议您再增加一个关注Postgres的对象。

@ypercubeᵀᴹ:我会在空闲的时候在这里添加答案。同时,我将dba.stackexchange.com/questions/49699/…更新为更加清晰和全面。

#1 楼

不,存储过程不会阻止SQL注入。这是一个不幸的允许SQL注入的存储过程的示例(来自内部创建的我在其内部工作的应用程序):

此sql server代码:

CREATE PROCEDURE [dbo].[sp_colunmName2]   
    @columnName as nvarchar(30),
    @type as nvarchar(30), 
    @searchText as nvarchar(30)           
AS
BEGIN
    DECLARE @SQLStatement NVARCHAR(4000)
    BEGIN
        SELECT @SQLStatement = 'select * from Stations where ' 
            + @columnName + ' ' + @type + ' ' + '''' + @searchText + '''' 
        EXEC(@SQLStatement)
    END      
END
GO


大致等效于postgres:用户想要的任何内容,都可以从小的Bobby表访问。

无论您使用SQL语句还是存储过程都无关紧要。重要的是您的SQL是使用参数还是串联的字符串。参数防止SQL注入;串联字符串允许SQL注入。

#2 楼

SQL注入攻击是将不受信任的输入直接附加到查询中的攻击,从而使用户可以有效地执行任意代码,如此规范的XKCD漫画所示。

因此,我们得到了以下情况:

userInput = getFromHTML # "Robert ') Drop table students; --"

Query = "Select * from students where studentName = " + userInput


由于通常不会对传入的参数进行解析,因此存储过程通常可以很好地防御SQL注入攻击。

在存储过程中,大多数数据库(和程序,不要忘记预编译的查询算作存储过程)如下:

 

create Stored procdure foo (
select * from students where studentName = :1
);



然后,当程序需要访问时,它调用foo(userInput)和很高兴检索结果。

存储过程并不是针对SQL-Injection的神奇防御措施,因为人们完全有能力编写不良的存储过程。但是,如果您了解SQL注入的工作方式,那么无论是存储在数据库中还是存储在程序中的预编译查询都更加困难。

您可以阅读有关SQL的更多信息-注入:


在Jeff Atwood的讨论中
预防备忘单

如何攻击自己的代码(确保您的QA包括安全测试。否则,您的网站将受到外部安全测试。这是一件坏事。)


#3 楼

是的,在某种程度上。
仅存储过程不会阻止SQL注入。

让我首先引用OWASP中的SQL注入


SQL注入攻击包括通过从客户端到应用程序的输入数据来插入或“注入” SQL查询。成功的SQL注入漏洞可以从数据库读取敏感数据,修改数据库数据(插入/更新/删除),对数据库执行管理操作(例如关闭DBMS),恢复DBMS文件上存在的给定文件的内容系统,并在某些情况下向操作系统发出命令。 SQL注入攻击是一种注入攻击,其中SQL命令被注入到数据平面输入中以实现预定义的SQL命令的执行。


即使使用存储过程,您也必须清理用户输入并且不要串联SQL语句。

Jeff Attwood在“给我参数化的SQL,否则就让我死亡”

以下是每当我听到SQL注入时就会浮现的有趣卡通漫画

我想你明白了:- )

看一下SQL注入预防作弊表,对预防方法进行了整洁的解释...

#4 楼

字符串连接是SQL注入的原因。使用参数设置可以避免这种情况。

存储过程通过在连接时强制执行无效的语法来增加安全性,但是如果在其中使用动态SQL则不是“安全”的。 >
因此,您的上面的代码是由这些字符串的连接引起的




幸运的是,这给出了无效的语法

对其进行参数化将给出

exec sp_GetUser 'x'' AND 1=(SELECT COUNT(*) FROM Client); --' , 'monkey'


这意味着



exec sp_GetUser ' = x' AND 1=(SELECT COUNT(*) FROM Client); --


' , ' = monkey


现在,在上面的代码中,您将没有行,因为我假设您没有用户'

如果存储的过程看起来像这样(使用串联动态SQL),则参数化的存储的proc调用仍将允许SQL注入

...
SET @sql = 'SELECT userName from users where userName = ''' + 
               @UserName + 
               ''' and userPass = ''' +
               @Password +
               ''''
EXEC (@sql)
....


因此,如所示,字符串连接是SQL注入的主要敌人

存储过程res确实添加了封装,事务处理,减少的权限等,但它们仍会被滥用以进行SQL注入。

您可以在Stack Overflow上查找有关参数化的更多信息

#5 楼

“ SQL注入攻击是在用户输入的编码不正确时发生的。通常,用户输入是用户随查询发送的一些数据,即$_GET$_POST$_COOKIE$_REQUEST$_SERVER数组中的值。但是,用户输入也可以来自各种其他来源,例如套接字,远程网站,文件等。因此,您应该将常量(例如'foobar')以外的所有内容都视为用户输入。”

我一直在深入研究关于此主题的最新知识,并希望与其他人分享非常有趣的材料,因此,使本帖子对每个人都更加完整和具有启发性。



用PHP防止SQL注入Nebel
安全角-Chris Shiflett的SQL注入
Alexander Andonov的意外SQL注入
Mylia_real_escape_string()与Ilia Alshanetsky的准备语句
Sagar Joshi的SQL注入攻击和防御
Jim Whiteh教授的SQL注入攻击Chris Shiflett撰写的ead
addslashes()与mysql_real_escape_string()vs

Joel Spolsky的SQL注入错误是什么


MySQL-防止SQL注入
/> SQL注入演练
SQL注入速查表
用PHP和MySQLi准备的语句





来自YouTube的


SQL注入的神话与谬论:Bill Karwin的最佳防御实践
PHP教程:安全-SQL注入
如何在Backtrack5 RC1上使用SQLMAP进行SQL注入

/>
来自Wikipedia


Wikipedia-SQL注入
Wikipedia-SQL


来自OWASP


SQL注入
SQL注入指南
OWASP-避免SQL注入
SQL注入预防速查表
测试SQL注入

>
来自PHP手册


SQL注入
PDO类-预备语句和存储过程
MySQL改进的扩展
mysql_real_escape_string()


来自Microsoft和Oracle



Microsoft防止PHP脚本中的SQL注入的正确方法是什么
阻止SQL注入攻击阻止您Microsoft
防御Oracle的SQL注入攻击


堆栈溢出


SQL注入和ADOdb库!常规PHP网站安全性示例-
防止PHP中进行SQL注入的最佳方法
XKCD SQL注入-请说明
避免SQL注入攻击的最佳方法是什么?
什么是SQL注入?
在INSERT上进行SQL注入
如何保护此函数免受SQL注入的侵害?
参数是否真的足以防止Sql注入?
今天SQL注入有风险吗?
/> SQL注入
SQL注入道德黑客
此代码是否阻止SQL注入?


SQL注入扫描程序


排名前15位的SQL注入扫描器
Netsparker社区版,免费的SQL注入扫描器和XSS扫描器


#6 楼

存储过程并不能神奇地阻止SQL注入,但是它们确实使阻止注入变得容易得多。您所要做的只是类似以下内容(Postgres示例):

CREATE OR REPLACE FUNCTION my_func (
  IN in_user_id INT 
)
[snip]
  SELECT user_id, name, address FROM my_table WHERE user_id = in_user_id; --BAM! SQL INJECTION IMMUNE!!
[snip]


就这样!仅在通过字符串串联(即动态SQL)形成查询时才会出现问题,即使在这种情况下,您也可以绑定! (取决于数据库。)

如何避免在动态查询中进行SQL注入:

步骤1)问问自己是否真的需要动态查询。如果您只是为了设置输入而将字符串粘在一起,那么您可能做错了。 (此规则有例外-一个例外是报告某些数据库上的查询,如果不强制每次执行都编译一个新查询,则可能会遇到性能问题。但是请在跳入该问题之前进行研究。 )

步骤2)研究为特定RDBMS设置变量的正确方法。例如,Oracle使您可以执行以下操作(引用其文档中的内容):

sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE ' 
           || v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value; --INJECTION IMMUNE!!


这里您仍然没有连接输入。您安全地绑定了!

如果您的数据库不支持上述功能(希望它们都还不算坏,但是我不会感到惊讶)-或者您是否仍然必须连接输入(例如(如我上文所述)在“有时”报告查询的情况下,则必须使用适当的转义功能。不要自己写。例如,postgres提供了quote_literal()函数。因此,您需要运行:

sql_stmt := 'SELECT salary FROM employees WHERE name = ' || quote_literal(in_name);


这样,如果in_name像'[snip]或1 = 1'这样的曲名(“ or 1 = 1”部分意味着选择所有行,让用户看到他不应该看到的薪水!),然后quote_literal通过生成结果字符串来节省您的屁股:

SELECT salary FROM employees WHERE name = '[snip] or 1=1'


找不到结果(除非您有一些名字很奇怪的员工。)

这就是要点!现在,让我留下Oracle专家Tom Kyte关于SQL Injection主题的经典文章的链接,以阐明这一点:Linky

评论


别忘了提到quote_ident()-但是通常,编写防注入动态SQL的最简单方法是使用format()并将占位符%I用作标识符,将%L用作文字。这样,与使用||的等效版本相比,SQL更具可读性。和quote _....()函数

– a_horse_with_no_name
18年6月25日在11:33