node-mysql query attempts to replace my question marks with parameters against my will - node.js

I'm trying to run a simple query with node-mysql like this:
client.query("UPDATE mytable SET emote='wtf?' WHERE id=5");
And I get the error
Error: too few parameters given
Because it found a question mark and expects parameters. How the heck do I tell it to ignore the question mark!? Escaping it with \ doesn't work. Passing ['?'] as a parameter is completely out of the question - what if I don't know the amount of question marks the query contains?
Currently I'm using a workaround that counts the amount of question marks in the query and passes that amount of question marks as parameters. But what if I were to actually need the parameters for what they were meant to do? I shiver at the thought.
So to summarize - How do I tell client.query() to ignore question marks?

Use this:
client.query('UPDATE mytable SET emote=? WHERE id=5', ['wtf?']);
Edit:
Passing ['?'] as a parameter is completely out of the question - what
if I don't know the amount of question marks the query contains?
I skipped over this. Why would you not know how many question marks the query contains? Why would you have an unknown query with question marks?

it's an unsolved bug: #118: Client.prototype.format shouldn't treat "?" as placeholder inside string literals

When I try to recreate your scenario, the repeat use of single quotes causes a problem:
client.query('UPDATE mytable SET emote='wtf?' WHERE id=5');
Specifically I see "SyntaxError: Unexpected identifier" when I try to launch the Node instance.
However, I'm able to run an equivalent query just fine, when I switch the outer quotes to double quotes, like so:
mysql.query("SELECT * FROM stories WHERE title='Test?'");
For comparison, this is the parameterized version of my query:
mysql.query('SELECT * FROM stories WHERE title=?',[req.params.title]);

Related

TypeORM to_tsquery Injection prevention

I want to perform a full-text-search on 2 columns with partial queries included.
I've tried multiple options and this one seems the best to me:
Add <-> between the words of the query and :* at the end
Execute query
The problem is, that I have to execute the query in TypeORM. So when I use to_tsquery(:query) there might be invalid syntax in the query, which produces an error.
The function plainto_tsquery() would be perfect since it prevents invalid syntax in the argument, but at the same time it prevents the partial queries, which I can do as described.
Any idea how I could combine the best of the to worlds?
You could try something like
SELECT to_tsquery(quote_literal(query) || ':*')
This will add <-> between word and :* at the end of every word, while quote_literal should protect you from syntax issues by escaping the text.
Disadvantage of this method however is that the generated query might behave unexpectedly when encountering queries with symbols, e.g. o'reilley as query will yield 'o':* <-> 'reilley':* as tsquery, which likely won't give back the expected result. Unfortunately, the only solution I know for this is cleaning both the input and text data of any symbols.

Why aren't the values inserted into the mysql2 query?

Can you tell me, please?
Why does the mysql2 value substitution not work inside the IN operator?
I do this, but nothing works.
Only the first character of the array is being substituted (number 6)
"select * from products_categories WHERE category_id IN (?)", [6,3]);
You can do it like this, of course:
IN(?,?,?,?,?,?,?,?,?,?) [6,3,1,1,1,1,1,1,1,1,1]
But that's not right, I thought that the IN should be automatically substituted from an array =(
I haven't used this, but my gut feeling tells that array items map to question marks based on indexes, so in your case 6 binds to first ? and 3 looks for another one, but doesn't find.
If I were you, I'd try to make sure that my first array item is then actually array, so I'd rewrite it:
"select * from products_categories WHERE category_id IN (?)", [[6,3]]);
I suspect you are using this with .execute(), which is short for prepared statements "prepare first if never executed before"+execute. While api is very similar to .query() one biggest difference is that in case of prepared statement only parameters are sent at execution time, unlike .query() where whole query text is interpolated with all parameters on the client. As a result, you need to send exactly the number of parameters as you have number of placeholders in original query text ( in you example - one ?). The whole [6,3,1,1,1,1,1,1,1,1,1] is treated as one parameter and sent to server as "6,3,1,1,1,1,1,1,1,1,1" string ( because during prepare step that parameter was likely reported by server as VAR_CHAR )
The solution is 1) use .query() and interpolate on the client or 2) build enough ?s dynamically and prepare different PS for different number of IN parameters

Cannot insert question mark in postgres insert

I'm trying to run a simple Postgres SQL insert:
insert into "Resources" values(1, 'How are you?');
But the result after insert is:
ID Data
--- ------
1 How are you$1
I know, to insert characters like single quote, I have to escape it with another single quote like: I can''t do it.
But what to do with ?
Knex interprets ? and ?? as positional bindings. You would normally use them inside a knex.raw() statement to safely inject some kind variable. For example:
knex.raw('UPDATE my_table SET my_column = ?', [someVariable])
Binding parameters like this is often necessary with raw statements to ensure whatever you're injecting is safely escaped.
So that's why you are seeing that behavior. The good news is, you can just escape question marks. From the Knex.js documentation:
To prevent replacement of ? one can use the escape sequence \\?.

How do I make a WHERE clause with SQLalchemy to compare to a string?

Objective
All I am trying to do is retrieve a single record from a specific table where the primary key matches. I have a feeling I'm greatly over complicating this as it seems to be a simple enough task. I have a theory that it may not know the variable value because it isn't actually pulling it from the Python code but instead trying to find a variable by the same name in the database.
EDIT: Is it possible that I need to wrap my where clause in an expression statement?
Attempted
My Python code is
def get_single_record(name_to_search):
my_engine = super_secret_inhouse_engine_constructor("sample_data.csv")
print("Searching for " + name_to_search)
statement = my_engine.tables["Users"].select().where(my_engine.tables["Users"].c.Name == name_to_search)
# Print out the raw SQL so we can see what exactly it's checking for
print("You are about to run: " + str(statement))
# Print out each result (should only be one)
print("Results:")
for item in my_engine.execute(statement):
print(item)
I tried hard coding a string in its place.
I tried using like instead of where.
All to the same end result.
Expected
I expect it to generate something along the lines of SELECT * FROM MyTable WHERE Name='Todd'.
Actual Result
Searching for Todd
STATEMENT: SELECT "Users"."Name", ...
FROM "Users"
WHERE "Users"."Name" = ?
That is an actual question mark appearing my statement, not simply my own confusion. This is then followed by it printing out a collection of all the records from the table, as though it successfully matched everything.
EDIT 2: Running either my own hard coded SQL string or the generated query by Alchemy returns every record from the table. I'm beginning to think the issue may be with the engine I've set up not accepting the query.
Why I'm Confused
According to the official documentation and third party sources, I should be able to compare to hardcoded strings and then, by proxy, be able to compare to a variable.

replaceAll quotes with backslashed quotes -- Is that enough?

I'm using replaceAll to replace single quotes with "\\\\'" per a colleague's suggestion, but I'm pretty sure that's not enough to prevent all SQL injections.
I did some googling and found this: http://wiki.postgresql.org/wiki/8.1.4_et._al._Security_Release_Technical_Info
This explains it for PostgreSQL, but does the replacing not work for all SQL managers? (Like, MySQL, for example?)
Also, I think I understand how the explanation I linked works for single backslash, but does it extend to my situation where I'm using four backslashes?
Please note that I'm not very familiar with databases and how they parse input, but this is my chance to learn more! Any insight would be appreciated.
Edit: I've gotten some really helpful, useful answers. My next question is, what kind of input would break my implementation? That is, if you give me input and I prepend all single quotes with four backslashes, what kind of input would you give me to inject SQL code? While I am convinced that my approach is naive and wrong, maybe some examples would better teach me how easy it is to inject SQL against my "prevention".
No, because what about backslashes? for instance if you turn ' into \' then the input \' will become \\' which is an unescaped single quote and a "character literal" backslash. For mysql there is mysql_real_escape_string() which should exist for every platform because its in the MySQL library bindings.
But there is another problem. And that is if you have no quote marks around the data segment. In php this looks like:
$query="select * from user where id=".$_GET[id];
The PoC exploit for this is very simple: http://localhost/vuln.php?id=sleep(10)
Even if you do a mysql_real_escape_string($_GET[id]) its still vulnerable to sqli because the attacker doesn't have to break out of quote marks in order to execute sql. The best solution is Parameterized Queries.
No.
This is not enough, and this is not the way to go. And I can say it without even knowing anything about your data, your SQL or even anything about your application. You should never, ever include any user data directly into your SQL. You should use parameterized statements instead.
Besides if you are asking this question you shouldn't write your own SQL by hand in the first place. Use a good ORM instead. Asking if your home-grown regular expression would make your application safe from SQL injection is like asking if your home-grown memory allocation routine that you have written in Assembly language is safe from buffer overruns - to which I would say: if you are asking this question then you should use a memory-safe language in the first place.
A simple case of SQL injection works like this (in pseudocode):
name = form_params["name"]
year = 2011
sql = "INSERT INTO Students (name, year) " +
"VALUES ('" + name + "', " + year + ");"
database_handle.query(sql)
year is supplied by you, the programmer, so it's not tainted, and can be embedded in the query in any way you find suitable; in this case — as an unquoted number.
But name is supplied by the user and so can be anything. Along comes Bobby Tables and inputs this value:
name = "Robert'); DROP TABLE Students; -- "
And the query becomes
INSERT INTO Students (name, year) VALUES ('Robert');
DROP TABLE Students; -- ', 2011);
That substitution turned your one query into two.
The first one gives an error because of the mismatched row count, but that doesn't matter, because the database is able to unambiguously find and run the second query. The attacker can work around the error by fiddling with the input anyway. The -- is a comment so that the rest of the input is ignored.
Note how data suddenly became code — a typical sign of a security problem.
What the suggested replacement does is this:
name = form_params["name"].regex_replace("'", "\\\\'")
How this works is confusing, hence my earlier comment. The string literal "\\\\'" represents the string \\'. The regex_replace function interprets that as the string \'. The database then sees
... VALUES ('Robert\'); DROP TABLE Students; -- ', 2011);
and interprets that correctly as a quite unusual name.
Among other problems this approach is very fragile. If the strings you use in your language don't substitute \\ as \, if your string substitution function doesn't interpret \\ as \ (if it's not a regex function or it uses $1 instead of \1 for backreferences) you could end up with an even number of slashes like
... VALUES ('Robert\\'); DROP TABLE Students; -- ', 2011);
and no SQL injection will be prevented.
The solution is not to check what the language and library does with all possible input you can think of, or to anticipate what it might do in a future version, but rather to use the facilities provided by the database. These usually come in two flavours:
database-aware escaping, which does exactly the right escaping of any data because the client library matches the server and it knows what the character encoding of the database you are querying is:
sql = "... '" + database_handle.escape(name) + "' ..."
out-of-band data submission (usually with prepared statments), so the data isn't even in the same string as the code:
sql = "... VALUES (:n, :y);"
database_handle.query(sql, n = name, y = year)

Resources