Is the following SQL susceptible to SQL injection via the #SearchWord parameter?
I want to use parameters with the FormsOf function, but the only guide to doing so I've found is in this Stack Overflow question: How to pass parameter to FormsOf function in sql server
However the solution seems to be to use a bit of dynamic SQL, and I was wondering if that would be susceptible to SQL injection. What would happen in the following example if #searchWord contained a SQL injection type string? Is it not a problem because it's still within a parameter, passed as an argument to FREETEXTTABLE?
The solution given is:
DECLARE #SearchWord nvarchar(max)
SET #SearchWord = 'tax'
DECLARE #SearchString nvarchar(max)
SET #SearchString = 'FormsOf(INFLECTIONAL, "' + #SearchWord + '")'
SELECT listing_id, RANK, name, address, city, zip, heading, phone
FROM listings a,
FREETEXTTABLE(listings, *, #SearchString)
WHERE [KEY] = a.listing_id
ORDER BY RANK DESC, name
No, it's not susceptible. There's no dynamic SQL here (that would require either using EXEC or sp_executesql), so there's no vector for SQL injection.
In order for a SQL injection vulnerability to exist, the user-supplied string (in this case #SearchWord) must actually be inserted directly into the text of the SQL statement. Here, it's only being used to construct another string variable, which is subsequently used as a parameter to another SQL statement.
This statement can, however, fail if the user inputs an "invalid" search word, i.e. one containing single quotes, so you should probably still escape whatever value is passed to #SearchWord. But it cannot be used to execute arbitrary SQL.
I haven't tested this, but I don't think the interpreter is simply pasting the value of #SearchString into the statement. It should parse #SearchString using the rules that FREETEXTTABLE expects--that's the way other parameters work.
Related
I have a Lookup that retrieves a few records from a MS SQL table containing schema, table name and a whole where clause. These values are passed to a copy data (within a ForEach) In the copy data i use a Dynamic query statement like:
#concat('select a.*, current_date as crt_tms from ',item().shm_nam,'.',item().tab_nam,
item().where_clause )
This construction works fine without the where_clause or with a where clause with an integer. But it goes wrong with strings like:
'a where a.CODSYSBRN ='XXX' ;'
it's about the quote (')
How can i pass it through?
I know that the where clause as a fixed string in the dynamic query works when i use double quotes (to escape the single quote):
'a where a.CODSYSBRN =''XXX'' ;'
Point is i need the where clause to be completely dynamic because it differ per table
whatever i try i get this kind of error:
Syntax error or access violation;257 sql syntax error: incorrect syntax near "where a"
ps i also tested this, but with the same result:
select a.*, current_date as crt_tms from #{item().shm_nam}.#{item().tab_nam} a #{item().where_clause}
As you have mentioned you are getting whole where clause from the lookup table, the query must have included the column values in where clause for string and integer types separately.
Example lookup table:
In your copy activity, you can use Concat() function as you were already doing it, to combine static values & parameters.
#concat('select * from ',item().schma_name,'.',item().table_name,' ',item().where_clause)
For debugging purposes, I have added the expression in set variable activity, to see the value of the expression.
Iteration1:
Iteration2:
I am trying to write a function that will dynamically create the sql statement, but I am facing problems with typecasts so, how can I identify using the type of field if it needs to be quoted
-- using this I can recover the types of each field
-- but I do not have a simple way to express that for a specific type it need
-- to quote
create table test (
id serial not null,
employee_name text,
salary decimal(12,2),
hire_date date,
active boolean
);
select column_name,data_type, null as need_to_be_quoted
from information_schema.columns
where table_name = 'table_name';
column type need to be quoted (this is a missing information)
-------------------------------------
id integer false
employee_name text true
salary decimal false
hire_date date true
active boolean false
quote_ident docs says:
Return the given string suitably quoted to be used as an identifier in an SQL statement string. Quotes are added only if necessary
But it is not what I was expecting:
insert into test (employee_name, salary, hire_date, active)
values (quote_identy('John Doe'), quote_identy(100000), quote_identy(current_date), quote_identy(true));
This is kind of necessary because I am trying to generate the statement string dinamically.
I have values to be inserted in some table, I can discover the type of each value, but to generated the insert string statement, I should know if a specific value type should be quoted or not for example
text: type should be quoted in the string statement
boolean: should not be quoted
numeric: should not be quoted
date: should be quoted
Don't quote. Quoting adds complexity and if you don't get it just right it has syntax and security issues.
Instead use bind parameters. The details depend on what database library you're working with, but the basic idea is always the same. First prepare the statement with placeholders for your values. Then execute it passing in the values. The database takes care of putting the values into the statement. You can execute the same prepared statement multiple times optimizing your coding and database calls.
Here's how you'd do it in PL/pgSQL with EXECUTE. The linked documentation has lots of information about safely executing dynamic queries.
do $$
begin
execute '
insert into test (employee_name, salary, hire_date, active)
values ($1, $2, $3, $4)
' using 'John Doe', 100000, current_date, true;
end;
$$;
Furthermore, while writing a SQL builder is a good exercise, it's also very complicated and very easy to get subtly wrong. There are plenty of libraries which will build SQL for you.
Here's your statement using PHP's Laravel.
DB::table('test')->insert([
'employee_name' => 'John Doe',
'salary' => 100000,
'hire_date' => current_date,
'active' => true
);
If you're curious about how SQL builders work, you can dig inside Laravel for ideas. Writing one in PL/pgSQL is ambitious, but I don't know of one that exists. Good luck!
We have a function that builds some XML and uses EXECUTE/USING to try to prevent SQL injection. It's along the lines of:
CREATE OR REPLACE FUNCTION public.f1(t TEXT)
RETURNS XML AS
$BODY$
DECLARE
ret_val XML;
BEGIN
EXECUTE 'SELECT ''<'' || $1 || ''>'''
--rest of xml building
INTO ret_val
USING t;
RETURN ret_val;
END
$BODY$
LANGUAGE plpgsql IMMUTABLE;
I don't like this much due to the concatenation. It would be much better if we could just do SELECT '''<$1>'' but that ends up with a literal $1 rather than replacing it with the value.
Due to the concatenation, it's making me wonder whether we even need SQL injection prevention here. It's not reading from a table, just building an XML string which is returned.
Is there any actual risk from not using USING in this case? Does concatenating $1 negate the effects of USING, or does USING even have any effect on a statement that doesn't use a table?
There are a few things to unpack here.
Firstly, the SQL you have there is actually a fixed string:
'SELECT ''<'' || $1 || ''>'''
So nothing can be directly injected here, because there's no dynamic SQL. As Laurenz Albe pointed out, the SQL in this particular example could be written as a non-dynamic statement:
SELECT '<' || t || '>'
There is still no SQL injection here, because you're not evaluating the contents of t, just manipulating it as a string, just as SELECT a + 1 would manipulate a as a number.
The key point is that the actual SQL is hard-coded, and the concatenation is just the instruction in that SQL.
Note that this similar-looking query would be dangerous (the syntax highlighting gives a clue to the difference):
EXECUTE 'SELECT ''<' || t || '>''' -- DON'T DO THIS!
Here, the value of t is being used as part of the SQL string - the concatenation is happening first, and then the result is executed. So a value of '1'; DROP TABLE users; --' would result in the query SELECT '<1'; DROP TABLE users; -- which is clearly undesirable.
Secondly, as explained in the docs, the $1 is a parameter, supplied by the USING clause as data, so it too is safe from SQL injection. This is similar to using a parameterised query in a programming language outside the database - you build up the query as a string, carefully whitelisting the tables and columns referenced, then provide the variable data separately, where it cannot be reinterpreted as SQL. Or to put it another way, it's like another function "one level deeper", with the parameters specified by the USING clause acting just like the parameters to an actual function.
Finally, though, a note of caution: you are vulnerable to XML injection: if nothing else has validated or escaped t, you could generate invalid or dangerous XML. For instance, consider what would happen if the value of t was 'foo><script>alert("Hello, world!");</script></foo' and the result ended up parsed as HTML.
There is no danger for SQL injection here, because you are using USING.
Note that you could have been using static SQL to achieve the same thing:
SELECT '<' || t || '>' INTO ret_val;
I am facing issue while storing jason value which has some text with single quotes.
Below is the scenario,
My Stored Procedure:
CREATE OR REPLACE FUNCTION JsonParse(inputdata json)
RETURNS void AS $$
DECLARE
BEGIN
UPDATE
MyTable
SET
settings_details= inputdata
WHERE
settings_key='my-list';
END;
$$
LANGUAGE PLPGSQL;
select * from JsonParse('[{
"myArray": ["New Text1 ''abcd''", "New Text1 ''abcd''"]
},
{"myArray": ["New Text1 ''abcd''", "New Text1 ''abcd''"]}]');
I get the below error :
ERROR: syntax error at or near "abcd"
I can add extra single quote to abcd and efgh. It solves the issue. But the problem is that i dont have control on the input text to JsonParse procedure.
The stored procedure should be capable enough to handle this.
May i please know on how to tackle this
Your stored procedure is not rejecting this, the SQL you are running is malformed.
Try a simpler example:
SELECT 'test o'reilly' AS FOO;
As the syntax highlighting shows, the SQL parser will think the string is 'test o', and the reilly is a syntax error.
This is a sign that you are not correctly handling data input into your SQL queries, and are probably vulnerable to SQL injection attacks (what if I supply you with the "JSON" string {}'); DROP TABLE users; --).
Everywhere that you add data to an SQL query, you need to do one of two things:
Escape the input using an appropriate function provided by your language or framework. This will mostly just be doubling apostrophes, but if implemented properly will ensure there aren't other characters that can break the input based on the database's character set etc.
Or, use parametrised prepared queries, where you write the SQL with placeholders, and then provide the data as a separate argument, which is transmitted separately, so cannot be mistaken for SQL (and, consequently, doesn't need quotes around strings). In your case, a parametrised query might look like this: select * from JsonParse(?); with the execute function taking one parameter.
I have a situation in a T-SQL stored procedure, where in a dynamic SQL, the parameter/s, referencing other variables, whose value has single quotes and other predefined operators. The problem is T-SQL script fails, when such a condition exist.
Attached is a sample code, demonstrating such a situation.
Any Idea how to solve such a case?
DECLARE #TransVocObj XML,#xmlfragment XML,#SQL NVARCHAR(MAX)
SELECT #TransVocObj = '<TransactionVoucherViewModel><TransactionRows></TransactionRows></TransactionVoucherViewModel>'
DECLARE #Narration varchar(100)
SET #Narration ='AABBCC''DD''EEFF'-- #Narration ='AABBCCDDEEFF'
Select #xmlfragment=
'<TransactionRow>'+'<Description>'+#Narration +'</Description>'+'<DebitAmount>'+CONVERT(VARCHAR(30),500.00)+'</DebitAmount>'+'</TransactionRow>'
SET #SQL=N' SET #TransVocObj.modify(''insert '+ CONVERT(NVARCHAR(MAX),#xmlfragment)+' into (/TransactionVoucherViewModel/TransactionRows)[1] '') '
EXECUTE sp_executesql #SQL,N'#TransVocObj XML Output,#xmlfragment XML',#TransVocObj OUTPUT,#xmlfragment
SELECT T.Item.query('.//Description').value('.','VARCHAR(60)') FROM #TransVocObj.nodes('//TransactionRows/TransactionRow') AS T(Item)
The database server is MS SQL SERVER 2005
You can double-up your single-quote characters within #Narration using the REPLACE function. So, when you build #xmlfragment it can look like:
Select #xmlfragment=
'<TransactionRow>'+'<Description>'+REPLACE(#Narration,'''','''''')+'</Description>'+'<DebitAmount>'+CONVERT(VARCHAR(30),500.00)+'</DebitAmount>'+'</TransactionRow>'