从 PL/SQL 中的集合创建 SQL- 注入证明动态 where-clause
Creating SQL-Injection proof dynamic where-clause from collection in PL/SQL
我需要执行一个查询,其中根据用户输入生成 where 子句。输入由 0 对或多对 varchar2 组成。
例如:
[('firstname','John')
,('lastname','Smith')
,('street','somestreetname')]
这将转化为:
where (attrib = 'firstname' and value = 'John')
and (attrib = 'lastname' and value = 'Smith')
and (attrib = 'street' and value = 'somestreetname')
这不是实际的数据结构,因为有几个 table,但是对于这个例子,让我们保持简单,假设值在 1 table 中。我也知道在这种情况下括号不是必需的,但我把它们放在那里是为了让事情更清楚。
我现在所做的是遍历它们并将它们连接到 SQL 字符串。我创建了一个存储过程来生成这个 where-clause 这可能也不是很安全,因为我只是连接到原始查询。
类似下面的内容,我尝试获取与请求的参数对应的节点的 ID:
l_query := select DISTINCT n.id from node n, attribute_values av
where av.node_id = n.id ' || getWhereClause(p_params)
open l_rc
for l_query;
fetch l_rc bulk collect into l_Ids;
close l_rc;
但这并不安全,所以我正在寻找一种可以保证安全并防止发生 SQL-注入攻击的方法。
有没有人知道这是如何以安全的方式完成的?我想使用绑定,但是当您不知道参数的数量时,我不知道如何做到这一点。
数据库:v12.1.0.2(我认为)
它仍然有点不清楚和概括,但假设你有一个架构级集合类型,比如:
create type t_attr_value_pair as object (attrib varchar2(30), value varchar2(30))
/
create type t_attr_value_pairs as table of t_attr_value_pair
/
然后您可以使用集合中的 attribute/value 对进行绑定:
declare
l_query varchar2(4000);
l_rc sys_refcursor;
type t_ids is table of number;
l_ids t_ids;
l_attr_value_pairs t_attr_value_pairs;
-- this is as shown in the question; sounds like it isn't exactly how you have it
p_params varchar2(4000) := q'^[('firstname','John')
,('lastname','Smith')
,('street','somestreetname')]^';
begin
-- whatever mechanism you want to get the value pairs into a collection;
-- this is just a quick hack to translate your example string
select t_attr_value_pair(rtrim(ltrim(
regexp_substr(replace(p_params, chr(10)), '(.*?)(,|$)', 1, (2 * level) - 1, null, 1),
'[('''), ''''),
rtrim(ltrim(
regexp_substr(replace(p_params, chr(10)), '(.*?)(,|$)', 1, 2 * level, null, 1),
''''), ''')]'))
bulk collect into l_attr_value_pairs
from dual
connect by level <= regexp_count(p_params, ',') / 2 + 1;
l_query := 'select DISTINCT id from attribute_values
where (attrib, value) in ((select attrib, value from table(:a)))';
open l_rc for l_query using l_attr_value_pairs;
fetch l_rc bulk collect into l_ids;
close l_rc;
for i in 1..l_ids.count loop
dbms_output.put_line('id ' || l_ids(i));
end loop;
end;
/
尽管这种方法不需要动态:
...
begin
-- whatever mechamism you want to get the value pairs into a collection
...
select DISTINCT id
bulk collect into l_ids
from attribute_values
where (attrib, value) in ((select attrib, value from table(l_attr_value_pairs)));
for i in 1..l_ids.count loop
dbms_output.put_line('id ' || l_ids(i));
end loop;
end;
/
或连接到 table 集合表达式:
select DISTINCT av.id
bulk collect into l_ids
from table(l_attr_value_pairs) t
join attribute_values av on av.attrib = t.attrib and av.value = t.value;
其他集合类型将需要不同的方法。
或者,您仍然可以为每个 attribute/value 对建立一个条件的 where
子句,同时仍然使它们绑定变量 - 但您需要两个级别的动态 SQL , similar to this.
我需要执行一个查询,其中根据用户输入生成 where 子句。输入由 0 对或多对 varchar2 组成。
例如:
[('firstname','John')
,('lastname','Smith')
,('street','somestreetname')]
这将转化为:
where (attrib = 'firstname' and value = 'John')
and (attrib = 'lastname' and value = 'Smith')
and (attrib = 'street' and value = 'somestreetname')
这不是实际的数据结构,因为有几个 table,但是对于这个例子,让我们保持简单,假设值在 1 table 中。我也知道在这种情况下括号不是必需的,但我把它们放在那里是为了让事情更清楚。
我现在所做的是遍历它们并将它们连接到 SQL 字符串。我创建了一个存储过程来生成这个 where-clause 这可能也不是很安全,因为我只是连接到原始查询。
类似下面的内容,我尝试获取与请求的参数对应的节点的 ID:
l_query := select DISTINCT n.id from node n, attribute_values av
where av.node_id = n.id ' || getWhereClause(p_params)
open l_rc
for l_query;
fetch l_rc bulk collect into l_Ids;
close l_rc;
但这并不安全,所以我正在寻找一种可以保证安全并防止发生 SQL-注入攻击的方法。
有没有人知道这是如何以安全的方式完成的?我想使用绑定,但是当您不知道参数的数量时,我不知道如何做到这一点。
数据库:v12.1.0.2(我认为)
它仍然有点不清楚和概括,但假设你有一个架构级集合类型,比如:
create type t_attr_value_pair as object (attrib varchar2(30), value varchar2(30))
/
create type t_attr_value_pairs as table of t_attr_value_pair
/
然后您可以使用集合中的 attribute/value 对进行绑定:
declare
l_query varchar2(4000);
l_rc sys_refcursor;
type t_ids is table of number;
l_ids t_ids;
l_attr_value_pairs t_attr_value_pairs;
-- this is as shown in the question; sounds like it isn't exactly how you have it
p_params varchar2(4000) := q'^[('firstname','John')
,('lastname','Smith')
,('street','somestreetname')]^';
begin
-- whatever mechanism you want to get the value pairs into a collection;
-- this is just a quick hack to translate your example string
select t_attr_value_pair(rtrim(ltrim(
regexp_substr(replace(p_params, chr(10)), '(.*?)(,|$)', 1, (2 * level) - 1, null, 1),
'[('''), ''''),
rtrim(ltrim(
regexp_substr(replace(p_params, chr(10)), '(.*?)(,|$)', 1, 2 * level, null, 1),
''''), ''')]'))
bulk collect into l_attr_value_pairs
from dual
connect by level <= regexp_count(p_params, ',') / 2 + 1;
l_query := 'select DISTINCT id from attribute_values
where (attrib, value) in ((select attrib, value from table(:a)))';
open l_rc for l_query using l_attr_value_pairs;
fetch l_rc bulk collect into l_ids;
close l_rc;
for i in 1..l_ids.count loop
dbms_output.put_line('id ' || l_ids(i));
end loop;
end;
/
尽管这种方法不需要动态:
...
begin
-- whatever mechamism you want to get the value pairs into a collection
...
select DISTINCT id
bulk collect into l_ids
from attribute_values
where (attrib, value) in ((select attrib, value from table(l_attr_value_pairs)));
for i in 1..l_ids.count loop
dbms_output.put_line('id ' || l_ids(i));
end loop;
end;
/
或连接到 table 集合表达式:
select DISTINCT av.id
bulk collect into l_ids
from table(l_attr_value_pairs) t
join attribute_values av on av.attrib = t.attrib and av.value = t.value;
其他集合类型将需要不同的方法。
或者,您仍然可以为每个 attribute/value 对建立一个条件的 where
子句,同时仍然使它们绑定变量 - 但您需要两个级别的动态 SQL , similar to this.