I have a function in postgres SQl which uses dynamic query to search results. I am using parameterized approach for the task to avoid SQL injection. below is the snippet from my function.
CREATE OR REPLACE FUNCTION master."FilterFooBar"(
"_Codes" character varying,
"_Chapter" character varying)
RETURNS TABLE("Foo" integer, "Bar" integer)
LANGUAGE 'plpgsql'
COST 100
VOLATILE PARALLEL UNSAFE
ROWS 1000
AS $BODY$
DECLARE
"_FromSql" TEXT;
BEGIN
"_FromSql" := ' FROM
master."FooBar" fb
WHERE
1 = 1';
IF "_Codes" IS NOT NULL
THEN
"_FromSql" := "_FromSql" || ' AND fb."Code" IN ('|| "_Codes" ||')';
END IF;
IF "_Chapter" IS NOT NULL
THEN
"_FromSql" := "_FromSql" || ' AND fb."Code" ILIKE '''|| "_Chapter" ||'%''';
END IF;
RETURN QUERY
EXECUTE
' SELECT fb."Foo",'|| ' fb."Bar",' || "_FromSql";
END
$BODY$;
The Problem here is this code
IF "_Chapter" IS NOT NULL
THEN
"_FromSql" := "_FromSql" || ' AND fb."Code" ILIKE '''|| "_Chapter" ||'%''';
END IF;
During testing I found out that it is vulnerable to SQL injection. If I just pass value like "_Chapter" = "01' or 8519=8519--"
it breaks my code. I thought dapper parameterized approach will solve the problem, but dapper does not handle this case. Is it because of dynamic query?
Any help is appreciated.
2
Answers
Turns out Dapper was escaping single quote to handle SQL injection, the problem was dynamic query. When malicious parameter was supplied like this
'01'' or 8519=8519--'
this statement"_FromSql" := "_FromSql" || ' AND fb."Code" ILIKE '''|| "_Chapter" ||'%''';
was getting converted toAND fb."Code" ILIKE '01' or 8519=8519-- %;
.To handle this, there is another way of writing dynamic query. Instead of using concatenation operator || we can use substitution using $ operator.
For e.g. above statement will be converted to
"_FromSql" := "_FromSql" || ' AND hs."Code" LIKE $2 ||''%'' ';
and you can pass actual parameters while executingThis will make sure to avoid unnecessary string termination
Why not put the dynamic sql into Dapper then using parameters should protect you from malicious code by throwing an exception (untested code follows):
called in your application like this: