MySQL loose comparison, WHERE on varchar field with integer value yields unexpected result

StackOverflow https://stackoverflow.com/questions/19895263

  •  30-07-2022
  •  | 
  •  

Domanda

I recently discovered an interesting bug in a program, which selects data for a specific customer using their private key. Consider the following:

SELECT `id` FROM (`customers`) WHERE `authenticationKey` = '#09209!ko2A-' LIMIT 1

The key is provided at request-time, and properly sanitized before put to query. However, failing to providing a key (which should be caught before; ignore that), would yield a query similar to the following:

SELECT `id` FROM (`customers`) WHERE `authenticationKey` = 0 LIMIT 1

Which would return a row from the customers-table - despite it having a proper, string, key stored, such as in the first example.

The authenticationKey-field is of the type VARCHAR(1024).

My guess is that this has something to do with loose comparasion. What is causing this problem, and how can it properly be avoided?

È stato utile?

Soluzione

MySQL will try and coerce data to a comparable type. I this case it will try and convert strings to numbers. Any strings that it can't make sense of default to 0.

Do

select 0 = 'banana'

to see this in action.

Making your query compare to '0' instead of 0 would fix it.

Example SQLFiddle

Altri suggerimenti

MySQL implicitly converts the leading chars of authenticationKey to int until it finds a char that's not a valid number. I guess all rows that start with a non-numeric char are treated as 0.

For instance, this yields 'b', since the coerced int value is 1:

select (case when '1abc' = 0 then 'a' else 'b' end);

But this yields 'a', since the leading char isn't a valid number, so the coerced int value is 0:

select (case when '#1abc' = 0 then 'a' else 'b' end);

This should be avoided by the application. Why you query with 0 when no key is given, after all?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top