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

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

  •  30-07-2022
  •  | 
  •  

문제

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?

도움이 되었습니까?

해결책

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

다른 팁

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?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top