【问题标题】:Sanitizing user inputs that are part of dynamic PL/SQL command清理作为动态 PL/SQL 命令一部分的用户输入
【发布时间】:2012-10-03 05:51:02
【问题描述】:


我有一个由用户填写的表,它的 VARCHAR2 记录包含可执行 PL/SQL 代码“IN(user_input)”的一部分。我想知道如何清理这些用户输入,或者重新编写它以提高效率。到目前为止,我所有的想法都失败了。例如:

  • 在这种情况下不接受绑定变量
  • DBMS_ASSERT.enquote_literal 总是引发异常等。

非常感谢您的帮助。

/* A "MY_PARAMETER" column is part of SQL: ...WHERE MY_DATA IN(MY_PARAMETER)... */
CREATE TABLE my_parameter_table (
       "ID" INTEGER NOT NULL ENABLE,
       "MY_PARAMETER" VARCHAR(255) NOT NULL ENABLE   
)

INSERT INTO my_parameter_table ("ID","MY_PARAMETER") VALUES (1,'6,7,8');
INSERT INTO my_parameter_table ("ID","MY_PARAMETER") VALUES (2,'''b'',''g'',''k''');
INSERT INTO my_parameter_table ("ID","MY_PARAMETER") VALUES (3,'SELECT dummy FROM dual'); -- return "X"

/* Tested table with data */
CREATE TABLE my_data_table (
       "ID" INTEGER NOT NULL ENABLE,
       "MY_DATA" VARCHAR(255) NOT NULL ENABLE,
       "MY_RESULT" VARCHAR(255) NOT NULL ENABLE   
);

INSERT INTO my_data_table ("ID","MY_DATA","MY_RESULT") VALUES (1,'a','NOT');
INSERT INTO my_data_table ("ID","MY_DATA","MY_RESULT") VALUES (2,'b','THIS'); --WILL PASS
INSERT INTO my_data_table ("ID","MY_DATA","MY_RESULT") VALUES (3,'c','NOT');
INSERT INTO my_data_table ("ID","MY_DATA","MY_RESULT") VALUES (4,'X','IS'); --WILL PASS
INSERT INTO my_data_table ("ID","MY_DATA","MY_RESULT") VALUES (5,'Y','NOT');
INSERT INTO my_data_table ("ID","MY_DATA","MY_RESULT") VALUES (6,'Z','CORRECT'); --WILL PASS

/* Result table where results are inserted */
CREATE TABLE my_result_table (
       "MESSAGE" VARCHAR(255) NOT NULL ENABLE   
);

/* ------------------------------------------- */

DECLARE
    where_condition VARCHAR2(1000) := '';
    v_query VARCHAR2(1000) := '';
    insert_or VARCHAR2(5) := '';

    CURSOR test_parameter_cur IS
        (
          SELECT * FROM my_parameter_table            
        );
    test_parameter_rec test_parameter_cur%ROWTYPE;

BEGIN

    /* Read all parameters and build an WHERE condition */
    OPEN test_parameter_cur;
    LOOP 
        FETCH test_parameter_cur INTO test_parameter_rec; 
        EXIT WHEN test_parameter_cur%NOTFOUND;

        /* Condition check can be any type. Varchar, number, date or some subselect */
        IF test_parameter_rec.ID = 1 THEN where_condition := where_condition || insert_or || 'd.ID IN('|| test_parameter_rec.MY_PARAMETER ||')';
        ELSE where_condition := where_condition || insert_or || 'd.MY_DATA IN('|| test_parameter_rec.MY_PARAMETER ||')';
        END IF;
        insert_or := ' OR '; -- after first run the "OR" operator is inserted in front of each where condition 

    END LOOP; 
    CLOSE test_parameter_cur; 

v_query := 'INSERT INTO my_result_table(MESSAGE) 
           (SELECT d.MY_RESULT FROM my_data_table d
           WHERE '|| where_condition ||')';

EXECUTE IMMEDIATE v_query;
COMMIT; 
END;

/* Now the my_result_table contains 3 records: THIS, IS, CORRECT */
SELECT * FROM my_result_table;

DROP TABLE my_parameter_table; 
DROP TABLE my_data_table;

【问题讨论】:

  • 您是否要授权您的用户输入子查询(例如 SELECT FROM DUAL)?
  • 脚本应该能够使用 IN 运算符评估各种参数集。参数由用户定义。除了直接编写 IN 参数之外,我不知道任何其他通用解决方案。尚未决定谁将填写参数(用户或管理员应要求),但无论如何都应该对其进行清理。这意味着例如允许 SELECT,但禁止 DROP。
  • 有一个例子,这个例子要简单得多。我仍然想知道,是否有任何方法可以使它安全。 user_input := '''a'',''b'',''c'''; /* OR / user_input := '1,2,3,4'; / OR / user_input := 'SELECT code FROM nationality'; / 一些功能依赖于很多东西。 */ where_condition := 'd.any_data_type_column IN(' || user_input || ')'; v_query := 'INSERT INTO my_result_table(result) (SELECT d.result_column FROM my_data_table d WHERE '|| where_condition ||')';立即执行 v_query;
  • 如果您让您的用户编写 SELECT,您相信他们会了解 SQL。我不会清理输入(除了将' 替换为'')。其他任何事情都将毫无意义。请记住,此功能很容易被滥用:您的用户几乎可以执行 SQL*Plus 对同一用户可以执行的任何操作。
  • 好的。谢谢你的建议。尽管用户是内部用户并且在某种程度上可以信任,但我会继续努力防止一些风险。我决定通过正则表达式检查用户输入。如果它有效,我可以分享它。

标签: plsql user-input dynamic-sql sanitization in-operator


【解决方案1】:

看看这里:https://blogs.oracle.com/aramamoo/entry/how_to_split_comma_separated_string_and_pass_to_in_clause_of_select_statement

就像',' - 分隔列表的魅力。我建议 TRIM() 结果从结果中删除尾随和前导空格。

您可以将 select 语句用作子句中的子选择。

【讨论】:

    猜你喜欢
    • 2018-09-05
    • 1970-01-01
    • 1970-01-01
    • 2018-01-14
    • 2013-09-14
    • 1970-01-01
    • 2016-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多