weird escape behaviour when writing string from node to mysql db - mysql

I'm on node and want to write this in my mysql db:
var x = JSON.stringify(['aa"a']);
console.log(x);
mysqlConnection.query("UPDATE `table` SET field = '" + x + "' WHERE id = 1");
The console.log() produces: ["aa\"a"]
When I read the string from the db later, I get: ["aa"a"]
The backslash is missing, making the string useless, as calling JSON.parse() would produce an error.

You're mashing your SQL together as a string. \ is an escape character (in SQL as well as JSON), so it escapes the " when passed to the SQL engine.
Use placeholders (whichever MySQL API library you are using should have a way of using them) instead of manually shoving variables into the string of SQL.

Related

how can I avoid sql inject when using "order by case when" in Golang?

there is a param representing userName;
I need to get some sorted records,if column "starred_by" contains 'userPrefix',it should be at the front,others should be at the end.
var userPrefix string; //userPrefix is a Request Param.
usePrefix = `%` + userPrefix + `%`
if userPrefix != "" {
order := fmt.Sprintf("CASE \nWHEN starred_by LIKE %q THEN 1\nELSE 2\nEND", userPrefix)
db = db.Order(order)
}
db = db.Order(otherParam1).Order(otherParam2)
db = db.Model(***).Scan(***)
the raw sql likes below:
SELECT * FROM `***` ORDER BY
CASE WHEN starred_by LIKE "%prefix1%" THEN 1 ELSE 2 END,otherParam1,otherParam2,otherParam3
but apparently this causes sql inject problem , how can i fix this?
the way to solve sql inject.
These elements cannot be bound into JDBC and gorm doesn't support them as parameterized queries or escape them - they are dangerous to use with untrusted input.
There are two options to do this safely - ideally you should use both:
Validate the columns in these via positive / whitelist validation. Each column name should be checked for existence in the associated tables.
You should enquote the column name - adding single quotes around the columns. If you do this, you need to be careful to validate there are no quotes in the name, and error out or escape any quotes. You also need to be aware that (in most databases) adding quotes will make the name case sensitive.

mysql query using python 3.6 (string variable is in single quotes)

I am new in python as well as mysql. I am having trouble in populating proper query statement for mysql.
sql = "SELECT * FROM Persons WHERE %s"
cur = db.cursor()
cur.execute(sql,(where,))
where is a string variable which creates a string for WHERE clause; this is the point of question. When I print this variable it give the following result:
Gender = True And IsLate = False
(without any quotes) but when I add this variable to the query to execute it, it adds single quotes around the string.
I used the command
print(cur.statement)
and it prints:
SELECT * FROM Persons WHERE 'Gender = True And IsLate = False'
After supplying parameter, it puts it within single quotes and query returns 0 rows.
I have worked around by concatenating the query statement and variable together and execute the string as query, that worked,
sql = sql + where
cur.execute(sql)
But I know that is not the professional way, as I have searched and found the professional way is to use parameterized query and use variable to store the condition(s) and supplying it at the execution of query.
Looking for advice, am I thinking the right way or otherwise?
The whole point of using parameter substitution in cursor.execute() is that it protects you from SQL injection. Each parameter is treated as a literal value, not substituted into the query and re-interpreted.
If you really want it to be interprted, you need to use string formatting or concatenation, as you discovered. But then you will have to be very careful in validating the input, because the user can supply extra SQL code that you may not have expected, and cause the query to malfunction.
What you should do is build the where string and parameter list dynamically.
where = []
params = []
if gender_supplied:
where.append('gender = %s')
params.append(gender)
if islate_supplied:
where.append*('islate = %s')
params.append(islate)
sql = 'select * from persons'
if where:
query = sql + ' where ' + ' and '.join(where)
else:
query = sql
cur.execute(query, params)

How to use Oracle's JSON_VALUE function with a PreparedStatement

I am trying to run a SQL query using Oracle's json_value() function using a PreparedStatement.
Assume the following table setup:
drop table foo cascade constraints purge;
create table foo
(
id integer primary key,
payload clob,
constraint ensure_json check (payload IS JSON STRICT)
);
insert into foo values (1, '{"data": {"k1": 1, "k2": "foo"}}');
The following SQL query works fine:
select *
from foo
where json_value(payload, '$.data.k1') = '1'
and returns the expected row.
However, when I try to run this query using a PreparedStatement like in the the following piece of code:
String sql =
"select *\n" +
"from foo\n" +
"where json_value(payload, ?) = ?";
PreparedStatement pstmt = conection.prepareStatement(sql);
pstmt.setString(1, "$.data.k1");
pstmt.setString(2, "1");
ResultSet rs = pstmt.executeQuery();
(I removed all error checking from the example to keep it simple)
This results in:
java.sql.SQLException: ORA-40454: path expression not a literal
The culprit is passing the json path value (parameter index 1), the second parameter is no problem.
When I replace (only) the first parameter with a String constant json_value(payload, '$.data.k1') = ? the prepared statement works fine.
In a desperate attempt, I also tried including the single quotes in the parameter: pstmt.setString(1, "'$.data.k1'") but not surprisingly, Oracle wouldn't accept it either (same error message).
I also tried using json_value(payload, concat('$.', ?) ) and only passing "data.k1" as the parameter - same result.
So, the question is:
How can I pass a JSON path expression to Oracle's json_value function using a PreparedStatement parameter?
Any ideas? Is this a bug in the driver or in Oracle? (I couldn't find anything on My Oracle Support)
Or is this simply a case of "not implemented"?
Environment:
I am using Oracle 18.0
I tried the 18.3 and 19.3 version of the ojdbc10.jar driver together with OpenJDK 11.
It isn't the driver - you get the same thing with dynamic SQL:
declare
result foo%rowtype;
begin
execute immediate 'select *
from foo
where json_value(payload, :1) = :2'
into result using '$.data.k1', '1';
dbms_output.put_line(result.payload);
end;
/
ORA-40454: path expression not a literal
ORA-06512: at line 4
And it isn't really a bug, it's documented (emphasis added):
JSON_basic_path_expression
Use this clause to specify a SQL/JSON path expression. The function uses the path expression to evaluate expr and find a scalar JSON value that matches, or satisfies, the path expression. The path expression must be a text literal. See Oracle Database JSON Developer's Guide for the full semantics of JSON_basic_path_expression.
So you would have to embed the path literal, rather than bind it, unfortunately:
declare
result foo%rowtype;
begin
execute immediate 'select *
from foo
where json_value(payload, ''' || '$.data.k1' || ''') = :1'
into result using '1';
dbms_output.put_line(result.payload);
end;
/
1 rows affected
dbms_output:
{"data": {"k1": 1, "k2": "foo"}}
or for your JDBC example (keeping the path as a separate string as you presumably want that to be a variable really):
String sql =
"select *\n" +
"from foo\n" +
"where json_value(payload, '" + "$.data.k1" + "') = ?";
PreparedStatement pstmt = conection.prepareStatement(sql);
pstmt.setString(1, "1");
ResultSet rs = pstmt.executeQuery();
Which obviously isn't what you want to do*, but there doesn't seem to be an alternative. Other than turning your query into a function and passing the path variable in to that, but then the function would have to use dynamic SQL, so the effect is much the same - maybe easier to handle SQL injection concerns that way though.
* and I'm aware you know how to do this the embedded way, and know you want to use bind variables because that's the correct thing to do; I've spelled it out more than you need for other visitors *8-)

SQL - Incorrect string value: '\xEF\xBF\xBD' [duplicate]

I have a table I need to handle various characters. The characters include Ø, ® etc.
I have set my table to utf-8 as the default collation, all columns use table default, however when I try to insert these characters I get error: Incorrect string value: '\xEF\xBF\xBD' for column 'buyerName' at row 1
My connection string is defined as
string mySqlConn = "server="+server+";user="+username+";database="+database+";port="+port+";password="+password+";charset=utf8;";
I am at a loss as to why I am still seeing errors. Have I missed anything with either the .net connector, or with my MySQL setup?
--Edit--
My (new) C# insert statement looks like:
MySqlCommand insert = new MySqlCommand( "INSERT INTO fulfilled_Shipments_Data " +
"(amazonOrderId,merchantOrderId,shipmentId,shipmentItemId,"+
"amazonOrderItemId,merchantOrderItemId,purchaseDate,"+ ...
VALUES (#amazonOrderId,#merchantOrderId,#shipmentId,#shipmentItemId,"+
"#amazonOrderItemId,#merchantOrderItemId,#purchaseDate,"+
"paymentsDate,shipmentDate,reportingDate,buyerEmail,buyerName,"+ ...
insert.Parameters.AddWithValue("#amazonorderId",lines[0]);
insert.Parameters.AddWithValue("#merchantOrderId",lines[1]);
insert.Parameters.AddWithValue("#shipmentId",lines[2]);
insert.Parameters.AddWithValue("#shipmentItemId",lines[3]);
insert.Parameters.AddWithValue("#amazonOrderItemId",lines[4]);
insert.Parameters.AddWithValue("#merchantOrderItemId",lines[5]);
insert.Parameters.AddWithValue("#purchaseDate",lines[6]);
insert.Parameters.AddWithValue("#paymentsDate",lines[7]);
insert.ExecuteNonQuery();
Assuming that this is the correct way to use parametrized statements, it is still giving an error
"Incorrect string value: '\xEF\xBF\xBD' for column 'buyerName' at row 1"
Any other ideas?
\xEF\xBF\xBD is the UTF-8 encoding for the unicode character U+FFFD. This is a special character, also known as the "Replacement character". A quote from the wikipedia page about the special unicode characters:
The replacement character � (often a black diamond with a white question mark) is a symbol found in the Unicode standard at codepoint U+FFFD in the Specials table. It is used to indicate problems when a system is not able to decode a stream of data to a correct symbol. It is most commonly seen when a font does not contain a character, but is also seen when the data is invalid and does not match any character:
So it looks like your data source contains corrupted data. It is also possible that you try to read the data using the wrong encoding. Where do the lines come from?
If you can't fix the data, and your input indeed contains invalid characters, you could just remove the replacement characters:
lines[n] = lines[n].Replace("\xFFFD", "");
Mattmanser is right, never write a sql query by concatenating the parameters directly in the query. An example of parametrized query is:
string lastname = "Doe";
double height = 6.1;
DateTime date = new DateTime(1978,4,18);
var connection = new MySqlConnection(connStr);
try
{
connection.Open();
var command = new MySqlCommand(
"SELECT * FROM tblPerson WHERE LastName = #Name AND Height > #Height AND BirthDate < #BirthDate", connection);
command.Parameters.AddWithValue("#Name", lastname);
command.Parameters.AddWithValue("#Height", height);
command.Parameters.AddWithValue("#Name", birthDate);
MySqlDataReader reader = command.ExecuteReader();
...
}
finally
{
connection.Close();
}
To those who have a similar problem using PHP, try the function utf8_encode($string). It just works!
I have this some problem, when my website encoding is utf-u and I tried to send in form CP-1250 string (example taken by listdir dictionaries).
I think you must send string encoded like website.

Issue with BigDecimal value in groovy : Retrieving diff value

I am using Groovy/Grails framework, I am fetching the Bigdecimal value from the mysql DB using the
Query = "select d.quantitativeData FROM MyTable d where d.segment.id = " + segmentid +
" and d.sustainabilityIndicatorSubQuestion.id = "+questionid+" and d.tenantId= " +
TenantUtils.getCurrentTenant()+" order by d.id desc",[max:1]"
quantitativeData is a Bidgecimal variable.
But the value is retrieved from this query is like "0E-20" format, but the value in the database like '121.00000000000' , How to resolve this, can anybody help me out.
Thanks in advance.
The BigDecimal is being converted to the string "0E-20", because you're constructing the query by concatenating strings together, rather than by using ? query placeholders.
If you use placeholders instead of string concatenation it will resolve this problem and also make you immune to SQL injection attacks.