使用regexp_replace来防止SQL注入

时间:2017-09-07 21:49:45

标签: oracle sql-injection dynamic-sql

我们有数千个包含map_products过程的oracle包。

我们有一个表,用于存储客户希望map_products运行的oracle包列表。

运行它们的进程使用动态SQL,如下所示:

select sanitize(package_name) 
  into v_package_name 
from   custom_plugins 
where  id = p_id;

execute immediate '
      begin 
          '||v_package_name||'.map_products; 
      end;
  ';

上面的清理功能是为了防止SQL注入。

这是函数定义:

function sanitize(p_string in varchar2) return varchar2
is
begin
    return regexp_replace(upper(p_string), 
              '(ALTER|MERGE|CREATE|SELECT|INSERT|UPDATE|DELETE|MODIFY|DROP|ENABLE|DISABLE|;)');
end;

现在我们意识到从长远来看这是一种危险的方法,并计划重做整个过程。但是,目前有没有简单的方法可以绕过这个regexp_replace来允许SQL注入?

更具体地说,我们希望确保不能传入分号。上述内容是否确保?

5 个答案:

答案 0 :(得分:3)

使用字符串:

DRDROPOP your_package_name

替换只会在您离开时替换DROP

DROP your_package_name

答案 1 :(得分:2)

我建议使用白名单而不是正则表达式。

根据系统表检查输入。

select object_name
from dba_objects
where owner = 'SYS'
and object_type = 'PACKAGE'
and object_name = :p_string;

如果找不到匹配项,那么它不是已知的包,所以不要使用它。

答案 2 :(得分:0)

我认为删除;将是避免sql注入的第一种方法。但请考虑这种可能的策略:

  1. 使用regexp从输入中提取有效的包名称(例如,检查您是否包含字母数字字符,或者" _",或者包名称中允许的任何其他字符,但没有其他字符。)
  2. 使用上一步的输出,检查包实际上是数据库中的对象(查询user_object)。
  3. 此时您将拥有一个有效的包名称(如果有),您可以在动态语句中使用它。
  4. 你已经说过你的做法很危险。我只是想确保你知道一个名字包含你的正则表达式中的任何单词的包(例如,salaryUPDATEr)会有问题

答案 3 :(得分:0)

正如上面的其他海报所评论,黑名单将很容易绕过。

使用白名单验证始终是理想选择。如果这不可行,并且由于这是Oracle,最好的选择是使用内置的dbms_assert.enquote_name - 这可以安全地引用该值(并检查嵌入的引号)。

有关DBMS_ASSERT的更多信息,请参阅: https://oracle-base.com/articles/10g/dbms_assert_10gR2#ENQUOTE_NAME

或者有关防止SQL注入的更深入的内容,请参阅: http://www.oracle.com/technetwork/database/features/plsql/overview/how-to-write-injection-proof-plsql-1-129572.pdf

答案 4 :(得分:0)

您可以使用DBMS_ASSERT软件包。 从10g版本开始,Oracle提供了DBMS_ASSERT软件包。它包含可用于验证用户输入的功能。

示例(尝试进行SQL注入)

SELECT description FROM products WHERE name=DBMS_ASSERT.ENQUOTE_LITERAL('abc'' OR 1=1--');

ERROR RETURNED.

ORA-06502: PL/SQL: numeric or value error

您可以在link上找到更多信息。