Loading

MYSQL中的where ‘1=1‘ 探讨

在学习MySQL时候,关于MySQL注入的例子

  1. 首先针对以下代码,实现的是关于sql注入时,一个普通登录所产生的的问题

    package com.java.lesson02;
    
    import com.java.lesson02.utils.JdbcUtils;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class SQLInjection {
        public static void main(String[] args) {
    //        login("kuangshen", "123");
            login(" 'or '1=1", " 'or '1=1");
        }
    
    
        private static void login(String username, String password) {
            Connection connection = null;
            Statement statement = null;
            ResultSet resultSet = null;
            try {
                connection = JdbcUtils.getConnection();
                statement = connection.createStatement();
    
                String sql = "SELECT * FROM users WHERE `NAME`='" + username + "' AND `PASSWORD`='" + password + "'";
                System.out.println(sql);
                resultSet = statement.executeQuery(sql);
                while (resultSet.next()) {
                    System.out.println("name=" + resultSet.getString("NAME"));
                    System.out.println("password=" + resultSet.getString("password"));
                    System.out.println("===========================================");
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
    
  2. 如果模拟登录时传入的参数是这样的话,login(" 'or '1=1", " 'or '1=1");,这样就产生了sql注入,可以看到的是,这样会获得所有用户的信息,因为这样进行模拟登录实际的sql语句是如下这样的:

    SELECT * FROM users WHERE `NAME`=' 'or '1=1' AND `PASSWORD`=' 'or '1=1';
    

为什么where中字符串’1=1’会将所有的信息查出来?

1.where中AND,OR运算符的优先级

sql中和大多数语言一样,AND运算符的优先级要高于OR运算符。所以针对上述的sql语句可以等同于如下语句

SELECT * FROM users WHERE (`NAME`=' ') or ('1=1' AND `PASSWORD`=' ') or ('1=1');

2.分析where中的’1=1’

​ 针对这个疑问我查阅了一些资料,在csdn上看到这样一篇博客的讲解,具体内容参见参考文献的第二篇。从上面分析过的sql语句可以看出,前两个括号中的条件肯定都是为假的(因为一般情况下NAME和password不为空),那么只有可能的是最后一个括号返回的bool值恒为真。

​ 但是最后一个括号中'1=1'是为字符串的也不是一个条件表达式,为什么返回的恒为true呢?这个疑问在一篇博客中得到了解答。

3.MySQL中把字符串强转成数字有三种方式

​ 下面举例说明

  1. SELECT CAST('123' AS SIGNED);

  2. SELECT CONVERT('123',SIGNED);

  3. SELECT '123'+0;

    CAST函数用法简介

    The CAST() function takes an expression of any type and produces a result value of a specified type, similar to CONVERT(). The syntax is:
    CAST(character_string AS character_data_type CHARACTER SET charset_name)
    Example:
    SELECT CAST(_latin1’test’ AS CHAR CHARACTER SET utf8);
    If you use CAST() without specifying CHARACTER SET, the resulting character set and collation are defined by the character_set_connection and collation_connection system variables. If you use CAST() with CHARACTER SET X, the resulting character set and collation are X and the default collation of X. You may not use a COLLATE clause inside a CONVERT() or CAST() call, but you may use it outside. For example, CAST(… COLLATE …) is illegal, but CAST(…) COLLATE … is legal:
    SELECT CAST(_latin1’test’ AS CHAR CHARACTER SET utf8) COLLATE utf8_bin;

    这是官方文档解释:

    大致用法就是CAST(字段名 AS 转换类型),其中针对字符串还可以设置字符集编码

    然后对于'1=1'

    MySQL中针对字符串不满足数字正则的字符串会取前面满足数字正则的获取

    举例说明如下:(这部分的内容参考了第二篇参考文章中的博客的内容,因为也是从那里得知的)

  4. 下面语句不会查询出任何结果

    SELECT *
    FROM users
    WHERE '啥玩意啊?1'+0;
    

    image-20200828154619282

  5. 但是稍微修改如下:

    SELECT *
    FROM users
    WHERE '1啥玩意啊'+0;
    

    只要在最前包含了满足数字正则的字符串,那么MySQL会将其取出来和后面的 0进行运算(如果没有后面的 0的话,会直接转换成数字),这就是上面的第三种转换。

    因为 '1啥玩意啊'中的 1被取出来了,那么1+0=1为真(因为0才为false,不为0的话为真),这样就将所有的结果查出来了。

    image-20200828155451959

    SELECT *
    FROM users
    WHERE '1啥玩意啊';
    

    这个sql语句的结果和上面一样,MySQL会将’1’取出来转化为数字1。

  6. 所以对于 where '1=1',mysql其实将其转化成了 where 1故恒为真,所以会将所有的信息查出来

    所以开始的sql语句转化成如今的样子:

    SELECT * FROM users WHERE ('1=1');
    

    ==>>转化成:

    SELECT * FROM users WHERE 1
    

    至此关于这个sql注入的例子探讨完毕。

参考文献

posted @ 2020-08-28 16:20  luwanglin  阅读(356)  评论(0编辑  收藏  举报