Oracle-11g-R2

如何使用綁定變數防止高度動態的 PL-SQL 查詢注入

  • July 15, 2020

我有一個程序,如下所示:

create or replace procedure Injection_test(qry1         varchar2,
                                          qry2         varchar2,
                                          user_id      varchar2) 
is
  final_query varchar2(1000) := '';
begin

 if (qry1 is not null) then
    final_query := 'select c_num from z_test_a where userid = ''' ||user_id || ''' and ' || qry1;
  if (qry2 is not null) then
    final_query := final_query || 'intersect  ';
  end if;
 end if;


if (qry2 is not null) then
 final_query := final_query || ' select c_num from z_test_b where userid = ''' ||user_id || ''' and ' || qry2;
end if;


--dbms_output.put_line(final_query);
 execute immediate 'insert into Z_final_result (c_num)'||final_query;
commit;
end;

如您所見,該變數final_query基於兩個輸入變數是高度動態的qry1 and qry2。由於我是 Oracle pl-sql injection 的新手,我不完全知道如何防止這段程式碼被 sql injection 。我知道注入的基本概念以及它是如何發生的——例如,當我們有null or 1=1一個輸入變數時,表的所有記錄都將插入到最終表中——但我不知道如何改變這個過程和用於bind variables防止注射發生。

我想知道你是否可以幫助我提前謝謝

我不確定有沒有好的答案。通常,使用字元串連接來建構 SQL 總是一個壞主意,應盡可能避免。也就是說,除了用綁定變數替換 user_id 引用之外,在您的情況下很難避免。除此之外,您將不得不提出一些自定義邏輯來驗證 qry1 和 qry2 的內容,以確保它們只包含您期望它們包含的內容。也許是長度限制,或者檢查關鍵字或列名?要麼這樣,要麼用每個表中列的顯式值(包括萬用字元)替換 qry1 和 qry2,然後將它們轉換為綁定變數。

只要您必須接受實際的 SQL 程式碼片段作為輸入,我會推薦如下內容:

create or replace procedure Injection_test(p_qry1         varchar2,
                                          p_qry2         varchar2,
                                          p_user_id      varchar2) 
is
  final_query varchar2(1000) := '';
begin

  -- put some logic here to validate the content of p_qry1 and p_qry2 to make sure
  -- they don't contain keywords like "select", "update", "delete", "1=1", ";" or
  -- equivalents, and/or that they do contain things you expect to see. Raise an
  -- application error anything unexpected is found

  if p_qry1 is not null
  then
     final_query := 'select c_num from z_test_a where userid = :user_id and ' 
                    || qry1;
     if p_qry2 is not null then
        final_query := final_query || ' intersect ';
     end if;
  end if;
  
  if p_qry2 is not null then
     final_query := final_query 
                    || 'select c_num from z_test_b where userid = :user_id and ' 
                    || qry2;
  end if;

  if final_query is not null
  then
     final_query := 'insert into Z_final_result (c_num) ' || final_query;
     --dbms_output.put_line(final_query);

     if instr(final_query,'intersect') > 1
     then   
        execute immediate final_query using p_user_id, p_user_id;
     else
        execute immediate final_query using p_user_id;
     end if;

     commit;
  end if;
end;

引用自:https://dba.stackexchange.com/questions/270918