JDBI using #bind for variables in queries inside quotes - objectquery

I'm wondering if/how this is possible, if it is, I'm sure its a simple fix that I can't seem to figure out
#SqlQuery("SELECT * FROM Table WHERE column LIKE '%:thingName%'")
public Set<Things> getThings(#Bind("thingName", String thingName)
Essentially for this toy example I am trying to select a row where a column contains [any text]thingName[anyText]. When using as above, I think the quotes obscure the bound variable so it literally looks for [any text]:thingName[anyText] and not my bound variable.
Thank you in advance,
Madeline

I use concat to surround input with % signs while still using a bound variable to avoid SQL injection:
#SqlQuery("select * from atable where acolumn like concat('%',:thingName,'%')")
public Set getNames(#Bind("thingName") String thingName);

It appears to be the case that you must add the '%' percentages to the bound variable:
#SqlQuery("SELECT * FROM Table WHERE column LIKE :thingName")
public Set<Things> getThings(#Bind("thingName") String thingName); // where thingName = "%" + thingName + "%"
See also: https://groups.google.com/forum/?fromgroups#!topic/jdbi/EwUi2jAEPdk
Quote from Brian McCallister
Using the :foo binding stuff creates a prepared statement and binds in the value for name in this case. You need the % to be part of the bound value, or you need to not use bindings to a prepared statement.
Approach 1 (the safer and generally better one):
"select … from foo where name like :name" and bind the value ("%" + name)
Approach 2 (which opens you up to sql injection):
"select … from foo where name like '%' " and define("name", name) (or in sql object, (#Define("name") name) -- which puts name in as a literal in your statement.
The key thing is that the % character is part of the value you are testing against, not part of the statement.

This must be the case with LIKE while binding variables. As per JDBI doc(Here) using SQL query concatenation can solve the issue. It worked for me.

Related

Dapper: Result from "SELECT COUNT(*) FROM TableName

I have the following code:
string sql = "SELECT COUNT(*) FROM " + tableName;
var rtn = DapperConnection.Query<int>(sql);
This works and bring back 1 record in the rtn variable. When I inspect the variable it seems to have 2 members, one is "[0]" and the other is "Raw View".
The member [0] is of type int and has the expected value, but I can't seem to get to that value in my code. This seems like a stupid question because I should be able to get to it, but can't. The latest try was the following:
int rtnCount = (int)rtn[0];
This however gave me a compiler error. How do I get to this value in my code?
Please don't do this! It's fragile, and introduces a gaping sql injection vulnerability. If you can return your count for a given table with one line of very expressive code, and no vulnerability, why make it method?
Do this instead:
DapperConnection.ExecuteScalar<int>("SELECT COUNT(*) FROM customers");
// You will be happier and live longer if you avoid dynamically constructing
// sql with string concat.
Use rtn.First() — it is an enumeration so that's the general way to get its first (and only in this case) item.

Use String parameter for RegEx in query

In my query (the database is a sql server) I use a RegEx for a select command like this:
SELECT * FROM test WHERE id LIKE '1[2,3]'
(This query is tested and returns the data I want)
I want to use a paramter for this RegEx. For that I definded the Paramter in iReport $P{id} as a string and the value is "1[2,3]".
In my query I use now this parameter like this:
SELECT * FROM test WHERE id LIKE $P{id}
As result I get a blank page. I think the problem is that the value of the parameter is defined with " ". But with ' ' I get a compiler error that the paramter isn't a string.
I hope someone can help me.
LIKE applies to text values, not to numeric values. Since id is numeric use something like this:
SELECT * FROM test WHERE id IN (12, 13)
with the parameter
SELECT * FROM test WHERE id IN ($P!{id_list})
and supply a comma separated list of ids for the parameter. The bang (!) makes sure that the parameter will be inserted as-is, without string delimiters.
Btw: LIKE (Transact-SQL) uses wildcards, not regex.
You can still use LIKE since there exists an implicit conversion from numeric types to text in T-SQL, but this will result in a (table or index) scan, where as the IN clause can take advantage of indexes.
The accepted answer works but it is using String replacement, read more about sql-injection, to understand why this is not good practice.
The correct way to execute this IN query in jasper report (using prepared statement) is:
SELECT * FROM test WHERE $X{IN, id, id_list}
For more information as the use of NOTIN, BETWEEN ecc. see JasperReports sample reference for query

Is it possible to concat strings in SOQL?

I've read thread from 2005 and people said SOQL does not support string concatenation.
Though wondering if it is supported and someone has done this.
I'm trying to concat but no luck :(
Below is APEX code trying to find record with specified email.
String myEmail = 'my#email.com';
String foo = 'SELECT emailTo__c, source__c FROM EmailLog__c
WHERE source__c = \'' +
myEmail + '\';
Database.query(foo)
Even though the record is indeed in the database, it does not query anything. Debug shows
"row(0)" which means empty is returned.
Am I doing concat wrong way?
UPDATE
I just found a way not have to add single quote. Just needed to apply same colon variable even for String that has query.
String foo = DateTime.newInstance(......);
String bar = 'SELECT id FROM SomeObject__c WHERE createdOn__c = :foo';
List<SomeObject__c> result = Database.query(bar);
System.debug(result);
This works too and is necessary if WHERE clause contains DateTime since DateTime cannot be surrounded with single quotes.
Why do you use Database.query()? Stuff will be much simpler and faster if you'll use normal queries in brackets
[SELECT emailTo__c, source__c FROM EmailLog__c WHERE source__c = :myEmail]
Not to mention that parameter binding instead of string concatenation means no need to worry about SQL injections etc.. Please consider getting used to these queries in brackets, they look weird in beginnign but will save your butt many times (mistyped field names etc).
As for actual concatenation - it works like you described it, I'm just unsure about the need to escape apostrophes. Binding the variables is safest way to go.
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_dynamic_soql.htm
http://www.salesforce.com/us/developer/docs/api/index_Left.htm#CSHID=sforce_api_calls_soql.htm|StartTopic=Content%2Fsforce_api_calls_soql.htm|SkinName=webhelp

Is there any C SQLite API for quoting/escaping the name of a table?

It's impossible to sqlite3_bind_text a table name because sqlite3_prepare_v2 fails to prepare a statement such as:
SELECT * FROM ? ;
I presume the table name is needed to parse the statement, so the quoting needs to have happened before sqlite3_prepare_v2.
Is there something like a sqlite3_quote_tablename? Maybe it already exists under a name I can't recognize, but I can't find anything in the functions list.
SQLite will escape identifiers for you with the %w format in the https://www.sqlite.org/printf.html family of functions.
your proposed sqlite3_quote_tablename function could sanitize the input to prevent sql injection attacks. To do this it could parse the input to make sure it is a string literal. http://sqlite.org/lang_expr.html#litvalue
If a table name has invalid characters in it you can enclose the table name in double quotes, like this.
sqlite> create table "test table" (id);
sqlite> insert into "test table" values (1);
sqlite> select * from "test table";
id
----------
1
Of course you should avoid using invalid characters whenever possible. It complicates development and is almost always unnecessary (IMO the only time it is necessary is when you inherit a project that is already done this way and it's too big to change).
When using SQLite prepared statements with parameters the parameter: "specifies a placeholder in the expression for a literal value that is filled in at runtime"
Before executing any SQL statement, SQLite "compiles" the SQL string into a series of opcodes that are executed by an internal Virtual Machine. The table names and column names upon which the SQL statement operates are a necessary part of the compilation process.
You can use parameters to bind "values" to prepared statements like this:
SELECT * FROM FOO WHERE name=?;
And then call sqlite3_bind_text() to bind the string gavinbeatty to the already compiled statement. However, this architecture means that you cannot use parameters like this:
SELECT * FROM ? WHERE name=?; // Can't bind table name as a parameter
SELECT * FROM FOO WHERE ?=10; // Can't bind column name as a parameter
If SQLite doesn't accept table names as parameters, I don't think there is a solution for your problem...
Take into account that:
Parameters that are not assigned values using sqlite3_bind() are treated as NULL.
so in the case of your query, the table name would be NULL which of course is invalid.
I was looking for something like this too and couldn't find it either. In my case, the expected table names were always among a fixed set of tables (so those were easy to validate). The field names on the other hand weren't so I ended up filtering the string, pretty much removing everything that was not a letter, number, or underscore (I knew my fields would fit this parameters). That did the trick.

Real examples of SQL injection issues for SQL Server using only a Replace as prevention?

I know that dynamic SQL queries are bad due to the SQL Injection issues (as well as performance and other issues). I also know that parameterized queries are prefered to avoid injection issues, we all know that.
But my client is still very stubborn and thinks that just
var UserName=Request.Form["UserName"];
UserName=UserName.Replace("'","''");
SQL="SELECT * FROM Users where UserName='" + UserName + "'";
Is enought protection against SQL injection issues against (SQL Server (Only), not mysql).
Can anyone give me real SQL Injection attack example that still can get through the Replace case above? Guess there's some unicode character issues?
I want some real live examples of attacks that still can get through that simple replace.
My question is only for SQL Server and I know that MySQL has some issues with the \ character.
This will not work if you are using NUMBERs.
"SELECT * FROM data WHERE id = " + a_variable + ";"
using
1;DROP TABLE users
Gives you
SELECT * FROM DATA WHERE id=1;DROP TABLE users;
Have a look at
SQL injection
MSDN SQL Injection
EDIT
Have a look at this. It is very close to your question
Proving SQL Injection
Please input your age : 21; drop table users;
SELECT * FROM table where age = 21; drop table users;
ouchies
I have some trouble understanding the scope of replacement. Your original line is:
SQL=SQL.Replace("''","'");
Because you apply it to the variable name SQL, I would assume you are replacing all occurrences of '' with ' in the entire statement.
This can't be correct: consider this statement:
SELECT * FROM tab WHERE col = '<input value goes here>'
Now, if is the empty string, the statement will be:
SELECT * FROM tab WHERE col = ''
...and after SQL.Replace("''", "'") it will become:
SELECT * FROM tab WHERE col = '
As you can see, it will leave a dangling single quote, and yields a syntax error.
Now, let's suppose you intended to write SQL.Replace("'", "''") then the replaced statement would become:
SELECT * FROM tab WHERE col = ''''
Although syntactically correct, you are now comparing col to a literal single quote (as the '' inside the outer single quotes that delimit the literal string will evaluate to a literal single quote). So this can't be right either.
This leads me to believe that you might be doing something like this:
SQL = "SELECT * FROM tab WHERE col = '" & ParamValue.Replace("'", "''") & "'"
Now, as was already pointed out by the previous poster, this approach does not work for number. Or actually, this approach is only applicable in case you want to process the input inside a string literal in the SQL stament.
There is at least on case where this may be problematic. If MS SQL servers QUOTED_IDENTIFIER setting is disabled, then literal strings may also be enclosed by double quote characters. In this case, user values injecting a double quote will lead to the same problems as you have with single quote strings. In addition, the standard escape sequence for a single quote (two single quotes) doesn't work anymore!!
Just consider this snippet:
SET QUOTED_IDENTIFIER OFF
SELECT " "" '' "
This gives the result:
" ''
So at least, the escaping process must be different depending on whether you delimit strings with single or with double quotes. This may not seem a big problem as QUOTED_IDENTIFIER is ON by default, but still. See:
http://msdn.microsoft.com/en-us/library/ms174393.aspx
Please see this XKCD cartoon:
Little Bobby Tables
The answers so far have been targeting on condition query with numeric datatypes and not having single quote in the WHERE clause.
However in MSSQL *at least in ver 2005), this works even if id is say an integer type:
"SELECT * FROM data WHERE id = '" + a_variable + "';"
I hate to say this but unless stored procedure (code that calls EXECUTE, EXEC, or sp_executesql) is used or WHERE clauses do not use quotes for numeric types, using single quote replacement will almost prevent possibility of SQL Injection. I cannot be 100% certain, and I really hope someone can prove me wrong.
I mentioned stored procedure due to second level injection which I only recently read about. See an SO post here on What is second level SQL Injection.
To quote from the accepted answer of the SO question "Proving SQL Injection":
[...] there is nothing inherently unsafe in a properly-quoted SQL statement.
So, if
String data is properly escaped using Replace("'","''") (and your SQL uses single quotes around strings, see Roland's answer w.r.t. QUOTED_IDENTIFIER),
numeric data comes from numeric variables and is properly (i.e. culture-invariantly) converted to string, and
datetime data comes from datetime variables and is properly converted to string (i.e. into one of the culture-invariant formats accepted by SQL Server).
then I cannot think of any way that SQL injection could be done in SQL Server.
The Unicode thing you mentioned in your question was a MySQL bug. Accounting for such problems in your code provides an extra layer of security (which is usually a good thing). Primarily, it's the task of the database engine to make sure that a properly-quoted SQL statement is not a security risk.
Your client is correct.
SQL = SQL.Replace("'","''");
will stop all injection attacks.
The reason this is not considered safe is that it's easy to miss one string entirely.

Resources