I'm using MySQL database with php. And found something strange.
Ex: I have table foo (with auto increment field id). When I do: select * from foo where id='1aoeu'; it's returning foo's row with id=1.
And when I do select * from foo where id='aoeu1'; it's returning nothing.
I think MySQL converting 1aoeu to int and returning 1 from that.
How to stop this? Is there any configuration for that?
You can't change the implementation of Mysql, you need to handle this case on application level. Clients and server side as well(on html form as well as on the server side when you handle this request).
Related
I've created a MySQL sproc which returns 3 separate result sets. I'm implementing the npm mysql package downstream to exec the sproc and get a result structured in json with the 3 result sets. I need the ability to filter the json result sets that are returned based on some type of indicator in each result set. For example, if I wanted to get the result set from the json response which deals specifically with Suppliers then I could use some type of js filter similar to this:
var supplierResultSet = mySqlJsonResults.filter(x => x.ResultType === 'SupplierResults');
I think SQL Server provides the ability to include a hard-coded column value in a SQL result set like this:
select
'SupplierResults',
*
from
supplier
However, this approach appears to be invalid in MySQL b/c MySQL Workbench is telling me that the sproc syntax is invalid and won't let me save the changes. Do you know if something like what I'm trying to achieve is possible in MySQL and if not then can you recommend alternative approaches that would help me achieve my ultimate goal of including some type of fixed indicator in each result set to provide a handle for downstream filtering of the json response?
If I followed you correctly, you just need to prefix * with the table name or alias:
select 'SupplierResults' hardcoded, s.* from supplier s
As far as I know, this is the SQL Standard. select * is valid only when no other expression is added in the selec clause; SQL Server is lax about this, but most other databases follow the standard.
It is also a good idea to assign a name to the column that contains the hardcoded value (I named it hardcoded in the above query).
In MySQL you can simply put the * first:
SELECT *, 'SupplierResults'
FROM supplier
Demo on dbfiddle
To be more specific, in your case, in your query you would need to do this
select
'SupplierResults',
supplier.* -- <-- this
from
supplier
Try this
create table a (f1 int);
insert into a values (1);
select 'xxx', f1, a.* from a;
Basically, if there are other fields in select, prefix '*' with table name or alias
Here's the story. I'm testing doing some security testing (using zaproxy) of a Laravel (PHP framework) application running with a MySQL database as the primary store for data.
Zaproxy is reporting a possible SQL injection for a POST request URL with the following payload:
id[]=3-2&enabled[]=on
Basically, it's an AJAX request to turn on/turn off a particular feature in a list. Zaproxy is fuzzing the request: where the id value is 3-2, there should be an integer - the id of the item to update.
The problem is that this request is working. It should fail, but the code is actually updating the item where id = 3.
I'm doing things the way I'm supposed to: the model is retrieved using Eloquent's Model::find($id) method, passing in the id value from the request (which, after a bit of investigation, was determined to be the string "3-2"). AFAIK, the Eloquent library should be executing the query by binding the ID value to a parameter.
I tried executing the query using Laravel's DB class with the following code:
$result = DB::select("SELECT * FROM table WHERE id=?;", array("3-2"));
and got the row for id = 3.
Then I tried executing the following query against my MySQL database:
SELECT * FROM table WHERE id='3-2';
and it did retrieve the row where id = 3. I also tried it with another value: "3abc". It looks like any value prefixed with a number will retrieve a row.
So ultimately, this appears to be a problem with MySQL. As far as I'm concerned, if I ask for a row where id = '3-2' and there is no row with that exact ID value, then I want it to return an empty set of results.
I have two questions:
Is there a way to change this behaviour? It appears to be at the level of the database server, so is there anything in the database server configuration to prevent this kind of thing?
This looks like a serious security issue to me. Zaproxy is able to inject some arbitrary value and make changes to my database. Admittedly, this is a fairly minor issue for my application, and the (probably) only values that would work will be values prefixed with a number, but still...
SELECT * FROM table WHERE id= ? AND ? REGEXP "^[0-9]$";
This will be faster than what I suggested in the comments above.
Edit: Ah, I see you can't change the query. Then it is confirmed, you must sanitize the inputs in code. Another very poor and dirty option, if you are in an odd situation where you can't change query but can change database, is to change the id field to [VAR]CHAR.
I believe this is due to MySQL automatically converting your strings into numbers when comparing against a numeric data type.
https://dev.mysql.com/doc/refman/5.1/en/type-conversion.html
mysql> SELECT 1 > '6x';
-> 0
mysql> SELECT 7 > '6x';
-> 1
mysql> SELECT 0 > 'x6';
-> 0
mysql> SELECT 0 = 'x6';
-> 1
You want to really just put armor around MySQL to prevent such a string from being compared. Maybe switch to a different SQL server.
Without re-writing a bunch of code then in all honesty the correct answer is
This is a non-issue
Zaproxy even states that it's possibly a SQL injection attack, meaning that it does not know! It never said "umm yeah we deleted tables by passing x-y-and-z to your query"
// if this is legal and returns results
$result = DB::select("SELECT * FROM table WHERE id=?;", array("3"));
// then why is it an issue for this
$result = DB::select("SELECT * FROM table WHERE id=?;", array("3-2"));
// to be interpreted as
$result = DB::select("SELECT * FROM table WHERE id=?;", array("3"));
You are parameterizing your queries so Zaproxy is off it's rocker.
Here's what I wound up doing:
First, I suspect that my expectations were a little unreasonable. I was expecting that if I used parameterized queries, I wouldn't need to sanitize my inputs. This is clearly not the case. While parameterized queries eliminate some of the most pernicious SQL injection attacks, this example shows that there is still a need to examine your inputs and make sure you're getting the right stuff from the user.
So, with that said... I decided to write some code to make checking ID values easier. I added the following trait to my application:
trait IDValidationTrait
{
/**
* Check the ID value to see if it's valid
*
* This is an abstract function because it will be defined differently
* for different models. Some models have IDs which are strings,
* others have integer IDs
*/
abstract public static function isValidID($id);
/**
* Check the ID value & fail (throw an exception) if it is not valid
*/
public static function validIDOrFail($id)
{
...
}
/**
* Find a model only if the ID matches EXACTLY
*/
public static function findExactID($id)
{
...
}
/**
* Find a model only if the ID matches EXACTLY or throw an exception
*/
public static function findExactIDOrFail($id)
{
...
}
}
Thus, whenever I would normally use the find() method on my model class to retrieve a model, instead I use either findExactID() or findExactIDOrFail(), depending on how I want to handle the error.
Thank you to everyone who commented - you helped me to focus my thinking and to understand better what was going on.
eg:
Table : user
column : user_id (type is int)
SELECT * FROM user WHERE user_id = '10xyz'
is giving same result of
SELECT * FROM user WHERE user_id = '10'
The input value is not integer but not giving an error in this case.
The reason why you are getting the same result is because MySQL automatically removes the trailing characters from the string and implicitly converts it to integer.
SQLFiddle Demo
SQLFiddle Demo (updated)
If you don't want to change all your code, but you have your database queries all going through one or a few subs, you can change those to check for warnings after using a statement handle (e.g. if ( $sth->{mysql_warning_count} ) ...).
Or you can create a DBI subclass that does that automatically for you, promoting warnings to errors. If you do, many others have use for such a thing. There are configuration settings to give an error instead of a warning when updating or inserting something like '10xyz' into an integer field, but not anything broader than that, and dear Oracle considers it Not a Bug. Maybe MariaDB does (or could do) better?
datatype of user_id is in database is INT
that why it giving same output and not error
I have an SQL table called "tbl_einheit". phpmyadmin shows more than 14.000 rows in the table. When accessing via webpage, the table is empty "eof".
I minimized the SQL Statment, and deleted all WHERE, ORDER BY elements, so that simply
SELECT * FROM tbl_einheit
is the statement. But it still returns an empty result set. I also tried
SELECT E . * FROM tbl_einheit E, ( SELECT #a := NULL ) AS init LIMIT 0,30
but also empty.
Any suggestions?
the reason is you have some data type in your mysql dtaabse that ADODB connector in ASSp can't recognize, so asp thinks it is EOF.
use CAST in MySQL to convert data type to something asp can understand, example:
SELECT CAST(SUM(Entry_Data_1) as UNSIGNED) as score FROM contests_entries
Put a trace in your code to make sure you are executing the code you think you are.
Double-check your connection string.
I have some problem regarding the search in mysql.
Below is my query.
SELECT * FROM table WHERE name LIKE "%admin\'s%";
When i am executing this query it will return zero data.
actually i have "admin\'s" stored in db. this "\" is to prevent sql injection. i have used mysql_real_escape_string to prevent the sql injection.
but when i use three times addslashes to my variable it works.
So my below query is working.
SELECT * FROM table WHERE name LIKE "%admin\\\\\\\'s%";
My above query will return the data with name like admin's.
I am not getting where i am wrong.
well for one you shouldnt have data like this in your DB admin\'s .. most likely you double escaped your string ( check if you don't have magic_quotes enabled on your server ).
If you only do
INSERT ... username = "admin\'s";
you will have in your db the username value admin's
so my recomandation would be to go ahead and remove the slashes from your database and then your first query should work.