Oracle - 为什么在存储过程中允许 EXECUTE IMMEDIATE?
Oracle - Why is EXECUTE IMMEDIATE allowed in stored procedures?
如果存储过程旨在减轻 SQL 注入攻击,为什么在存储过程中允许 EXECUTE IMMEDIATE?以下问题的公认答案将它们称为针对此类攻击的步骤:
What is a stored procedure?
"Stored procedures also have a security benefit in that you can grant
execute rights to a stored procedure but the user will not need to
have read/write permissions on the underlying tables. This is a good
first step against SQL injection."
...除非存储过程正在使用 EXECUTE IMMEDIATE。
此PL/SQL代码returns产品描述(第二个参数)。
CREATE OR REPLACE PROCEDURE prodDescr(vname IN VARCHAR2, vresult OUT VARCHAR2) AS
vsql VARCHAR2(4000);
BEGIN
vsql := 'SELECT description FROM products WHERE name=''' || vname || '''';
EXECUTE IMMEDIATE vsql INTO vresult;
END;
恶意用户输入。
A' AND 1=2 UNION SELECT password FROM members WHERE username='admin
生成的查询。
SELECT description FROM products WHERE name='A' OR 1=2 UNION SELECT password FROM members WHERE username='admin'
执行查询时,攻击者获取管理员密码
如您所见,尽管我们使用了存储过程,但攻击者仍然可以利用漏洞,就像我们是业余开发人员在 PHP 中连接一些 SELECT 语句而不进行清理一样容易输入。对我来说,对开发人员说存储过程将有助于保持数据库安全似乎是一种误导。
仍然可以安全地使用“立即执行”。这一切都归结为存储过程的逻辑。 concat 使代码不安全而不是立即执行。
vsql := 'SELECT description FROM products WHERE name=''' || vname || '''';
应该使用绑定变量或 dbms_assert 调用。
vsql := 'select count(1) from all_objects where owner = :1'
EXECUTE IMMEDIATE vsql into vresult using vname ;
或
vsql := 'select count(1) from all_objects where owner ='||DBMS_ASSERT.ENQUOTE_LITERAL(vname);
EXECUTE IMMEDIATE vsql into vresult ;
在下面使用这两种方法的完整示例中。第一个有绑定,第二个用 DBMS_ASSERT.
包装
SQL>declare
v_in varchar2(2000);
ret varchar2(2000);
begin
v_in := 'KLRICE';
EXECUTE IMMEDIATE 'select count(1) from all_objects where owner = :1' into ret using v_in ;
dbms_output.put_line('First Object Count : ' || ret);
EXECUTE IMMEDIATE 'select count(1) from all_objects where owner ='||DBMS_ASSERT.ENQUOTE_LITERAL(v_in) into ret ;
dbms_output.put_line('Second Object Count : ' || ret);
end
SQL> /
First Object Count : 74
Second Object Count : 74
PL/SQL procedure successfully completed.
SQL>
存储过程不能保证数据库安全。这从来都不是真的。
没有任何语言、框架或 API 可以保证您的数据库安全。
编写安全代码是开发人员的责任。
如果您以不安全的方式使用 EXECUTE IMMEDIATE,那么您就有漏洞了。
当您不使用存储过程时也是如此 — 如果您使用任何应用程序语言编写动态 SQL,您将面临创建 SQL 注入漏洞的相同风险。
如果存储过程旨在减轻 SQL 注入攻击,为什么在存储过程中允许 EXECUTE IMMEDIATE?以下问题的公认答案将它们称为针对此类攻击的步骤:
What is a stored procedure?
"Stored procedures also have a security benefit in that you can grant execute rights to a stored procedure but the user will not need to have read/write permissions on the underlying tables. This is a good first step against SQL injection."
...除非存储过程正在使用 EXECUTE IMMEDIATE。
此PL/SQL代码returns产品描述(第二个参数)。
CREATE OR REPLACE PROCEDURE prodDescr(vname IN VARCHAR2, vresult OUT VARCHAR2) AS
vsql VARCHAR2(4000);
BEGIN
vsql := 'SELECT description FROM products WHERE name=''' || vname || '''';
EXECUTE IMMEDIATE vsql INTO vresult;
END;
恶意用户输入。
A' AND 1=2 UNION SELECT password FROM members WHERE username='admin
生成的查询。
SELECT description FROM products WHERE name='A' OR 1=2 UNION SELECT password FROM members WHERE username='admin'
执行查询时,攻击者获取管理员密码
如您所见,尽管我们使用了存储过程,但攻击者仍然可以利用漏洞,就像我们是业余开发人员在 PHP 中连接一些 SELECT 语句而不进行清理一样容易输入。对我来说,对开发人员说存储过程将有助于保持数据库安全似乎是一种误导。
仍然可以安全地使用“立即执行”。这一切都归结为存储过程的逻辑。 concat 使代码不安全而不是立即执行。
vsql := 'SELECT description FROM products WHERE name=''' || vname || '''';
应该使用绑定变量或 dbms_assert 调用。
vsql := 'select count(1) from all_objects where owner = :1'
EXECUTE IMMEDIATE vsql into vresult using vname ;
或
vsql := 'select count(1) from all_objects where owner ='||DBMS_ASSERT.ENQUOTE_LITERAL(vname);
EXECUTE IMMEDIATE vsql into vresult ;
在下面使用这两种方法的完整示例中。第一个有绑定,第二个用 DBMS_ASSERT.
包装SQL>declare
v_in varchar2(2000);
ret varchar2(2000);
begin
v_in := 'KLRICE';
EXECUTE IMMEDIATE 'select count(1) from all_objects where owner = :1' into ret using v_in ;
dbms_output.put_line('First Object Count : ' || ret);
EXECUTE IMMEDIATE 'select count(1) from all_objects where owner ='||DBMS_ASSERT.ENQUOTE_LITERAL(v_in) into ret ;
dbms_output.put_line('Second Object Count : ' || ret);
end
SQL> /
First Object Count : 74
Second Object Count : 74
PL/SQL procedure successfully completed.
SQL>
存储过程不能保证数据库安全。这从来都不是真的。
没有任何语言、框架或 API 可以保证您的数据库安全。
编写安全代码是开发人员的责任。
如果您以不安全的方式使用 EXECUTE IMMEDIATE,那么您就有漏洞了。
当您不使用存储过程时也是如此 — 如果您使用任何应用程序语言编写动态 SQL,您将面临创建 SQL 注入漏洞的相同风险。