淘先锋技术网

首页 1 2 3 4 5 6 7

问题

在学 sql 注入的时候,总是搞不明白 mysql 的查询条件 WHERE 子句的引号的问题。例如,对于下面这个表

各字段的类型如下

可以看到 id 字段是 INT 类型。然后进行如下的查询。

可以看到有的感觉是明显不正确的查询条件还是可以查询出来的。然后,我就想是不是 mysql 对引号的匹配处理的问题。但是从上面的最后一个示例图片来看,好像并不是单纯的引号的问题。后来查了一下应该是 Mysql隐式类型转换 的问题。

如下图所示,是将字符串转换为 INT。

Mysql成功地将 '1 "222" 333'转换成了 1。虽然这个显式的类型转换,但是大概可以理解上面那些图片里的查询了,就是发生了隐式的类型转换,将字符串转换成了 INT,然后就查询出来了。

解释

在 Mysql 中,当一个操作符用来比较两个不同类型的时候,就会发生隐式的类型转换。具体的转换规则如下。

If one or both arguments are NULL, the result of the comparison is NULL, except for the NULL-safe <=> equality comparison operator. For NULL <=> NULL, the result is true. No conversion is needed.

如果一个或两个参数均为NULL,则比较的结果为NULL,除了NULL-safe <=> 相等比较运算符外。对于NULL <=> NULL,结果为true。无需转换。

If both arguments in a comparison operation are strings, they are compared as strings.

如果比较操作中的两个参数都是字符串,则将它们作为字符串进行比较。

If both arguments are integers, they are compared as integers.

如果两个参数都是整数,则将它们作为整数进行比较。

Hexadecimal values are treated as binary strings if not compared to a number.

如果不与数字比较,则将十六进制值视为二进制字符串。

If one of the arguments is a TIMESTAMP or DATETIME column and the other argument is a constant, the constant is converted to a timestamp before the comparison is performed. This is done to be more ODBC-friendly. This is not done for the arguments to IN(). To be safe, always use complete datetime, date, or time strings when doing comparisons. For example, to achieve best results when using BETWEEN with date or time values, use CAST() to explicitly convert the values to the desired data type.

如果参数之一是a TIMESTAMP或 DATETIMEcolumn,而另一个参数是常量,则在执行比较之前,该常量将转换为时间戳。这样做是为了使ODBC更友好。对于的参数,此操作未完成 IN()。为了安全起见,在进行比较时,请始终使用完整的日期时间,日期或时间字符串。例如,为了在BETWEEN与日期或时间值一起使用时获得最佳结果 ,可使用CAST()将值显式转换为所需的数据类型。

A single-row subquery from a table or tables is not considered a constant. For example, if a subquery returns an integer to be compared to a DATETIME value, the comparison is done as two integers. The integer is not converted to a temporal value. To compare the operands as DATETIME values, use CAST() to explicitly convert the subquery value to DATETIME.

一个或多个表中的单行子查询不视为常量。例如,如果子查询返回要与DATETIME 值进行比较的整数,则比较将作为两个整数完成。整数不转换为时间值。要将操作数作为DATETIME值进行比较 ,请使用 CAST()将子查询值显式转换为DATETIME。

If one of the arguments is a decimal value, comparison depends on the other argument. The arguments are compared as decimal values if the other argument is a decimal or integer value, or as floating-point values if the other argument is a floating-point value.

如果参数之一是十进制值,则比较取决于另一个参数。如果另一个参数是十进制或整数值,则将参数作为十进制值进行比较;如果另一个参数是浮点值,则将参数作为浮点值进行比较。

In all other cases, the arguments are compared as floating-point (real) numbers. For example, a comparison of string and numeric operands takes place as a comparison of floating-point numbers.

在所有其他情况下,将参数作为浮点数(实数)进行比较。例如,将字符串和数字操作数进行比较,将其作为浮点数的比较。

上面截图中的应该就是最后一种情况。当作浮点数进行比较。以'1 "222" 333'为例,首先将其从左向右取出数字部分转换为浮点数,然后跟表中的记录进行比较。

注意

避免发生隐式类型转换,隐式转换的类型主要有字段类型不一致、in参数包含多个类型、字符集类型或校对规则不一致等

隐式类型转换可能导致无法使用索引、查询结果不准确等,因此在使用时必须注意

数字类型的建议在字段定义时就定义为int或者bigint,表关联时关联字段必须保持类型、字符集、校对规则都一致

当字符串转换为浮点数时,数字位数至少在17位就会出现问题。

参考