zoukankan      html  css  js  c++  java
  • pymysql的使用及sql注入

    pymysql简介

    pymysql是python操纵mysql的一个模块,本质上是一个socket客户端


    ## pymysql使用

    准备数据

    #创建数据库db2,如果已存在,请忽略
    CREATE DATABASE db2 DEFAULT CHARACTER SET utf8;
    #创建用户表
    CREATE TABLE `userinfo` (
      `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
      `username` varchar(20) NOT NULL COMMENT '用户名',
      `password` varchar(32) NOT NULL COMMENT '密码',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';
    
    #插入一条数据
    INSERT INTO `db2`.`userinfo` (`id`, `username`, `password`) VALUES ('1', 'helln', '123');
    
    

    ### 实现

    使用Python实现用户登录,如果用户存在则登录成功(假设该用户已在数据库中)

    #导入模块
    import pymysql
    
    user = input('请输入用户名:')
    pwd = input('请输入密码:')
    
    # 1.连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='', db='db2', charset='utf8')
    
    # 2.创建游标
    cursor = conn.cursor()
    
    # 注意%s需要加引号
    sql = "select * from userinfo where username='%s' and password='%s'" % (user, pwd)
    print('sql语句:',sql)
    
    # 3.执行sql语句
    cursor.execute(sql)
    
    result = cursor.execute(sql)  # 执行sql语句,返回sql查询成功的记录数目
    print('返回记录数:',result)
    
    # 关闭连接,游标和连接都要关闭
    cursor.close()
    conn.close()
    
    if result:
        print('登陆成功')
    else:
        print('登录失败')
    
    

    演示

    输入正确用户名和密码

    请输入用户名:helln
    请输入密码:123
    sql语句: select * from userinfo where username='helln' and password='123'
    返回记录数: 1
    登陆成功
    

    输入错误时 ``` 请输入用户名:helln 请输入密码:234 sql语句: select * from userinfo where username='helln' and password='234' 返回记录数: 0 登录失败
    
    <br>
    ## sql注入
    
    sql注入有两种形式:用户名存在绕过密码、用户不存在绕过用户名和密码
    
    ### 用户名存在绕过密码
    格式
    
    

    存在的用户名' -- 任意字符
    或者
    存在的用户名' #任意字符

    <br>
    测试'--
    

    请输入用户名:helln' -- skdjfskdf
    请输入密码:sdf
    sql语句: select * from userinfo where username='helln' -- skdjfskdf' and password='sdf'
    返回记录数: 1
    登陆成功

    ![](https://img2018.cnblogs.com/blog/1542801/201904/1542801-20190406203845450-1859590627.png)
    
    
    <br>
    测试' #
    

    请输入用户名:helln' #lsjefls
    请输入密码:woieurweio
    sql语句: select * from userinfo where username='helln' #lsjefls' and password='woieurweio'
    返回记录数: 1
    登陆成功

    ![](https://img2018.cnblogs.com/blog/1542801/201904/1542801-20190406203917915-1917128048.png)
    
    在navicat中可以看到-- 和#后面的都被注释掉了,所以只有username='helln'起作用,自然也就能够查询到结果
    
    <br>
    ### 用户名不存在,绕过用户名和密码
    
    格式
    

    任意用户名' or 1=1 -- 任意字符
    或者
    任意用户名' or 1=1 #任意字符
    或者
    任意用户名' or '任意字符'='任意字符

    <br>
    注意:
    - 用户名后面有一个单引号
    - or前后都有空格
    - 必须保证等式成立
    
    <br>
    测试
    

    请输入用户名:sfhgk' or 1=1 -- sfjeor
    请输入密码:vnxlngf' or 2=2 #sdfwer
    sql语句: select * from userinfo where username='sfhgk' or 1=1 -- sfjeor' and password='vnxlngf' or 2=2 #sdfwer'
    返回记录数: 1
    登陆成功

    
    <b><font color='#ff0000'>sql注入的本质是(通过注释)构造恒为真的表达式绕过验证</font></b>
    
    
    <br>
    ## 解决办法
    
    原来我们是用字符串拼接做的
    ```python
    sql="select * from userinfo where name='%s' and password='%s'" %(username,pwd)
    print(sql)
    result=cursor.execute(sql)
    
    

    将上面的语句改为下面这样,注意一定不要再加引号了

    #改写为(execute帮我们做字符串拼接,我们无需且一定不能再为%s加引号了)
    sql="select * from userinfo where name=%s and password=%s" #!!!注意%s需要去掉引号,因为pymysql会自动为我们加上
    result=cursor.execute(sql,[user,pwd]) #pymysql模块自动帮我们解决sql注入的问题,只要我们按照pymysql的规矩来。
    
    

    ## commit()提交 在数据库里增、删、改的时候,必须要进行提交,否则插入的数据不生效。
    ### 增
    #导入模块
    import pymysql
    
    user = input('请输入用户名:')
    pwd = input('请输入密码:')
    
    # 1.连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='', db='db2', charset='utf8')
    
    # 2.创建游标
    cursor = conn.cursor()
    
    sql = "insert into userinfo(username,password) values (%s,%s)"
    print('sql语句:',sql)
    
    # 3.执行sql语句,返回sql查询成功的记录数
    #同时插入多条数据
    result = cursor.executemany(sql,[(user+'1',pwd),(user+'2',pwd)])
    print('返回记录数:',result)
    
    #一定记得commit
    conn.commit()
    
    # 关闭连接,游标和连接都要关闭
    cursor.close()
    conn.close()
    
    #判断结果
    if result:
        print('ok')
    else:
        print('error')
    
    

    ### 改 ```python #!/usr/bin/env python # -*- coding: utf-8 -*- #导入模块 import pymysql

    user = input('请输入用户名:')
    pwd = input('请输入密码:')

    1.连接

    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='', db='db2', charset='utf8')

    2.创建游标

    cursor = conn.cursor()

    sql = "update userinfo set username = %s where id = '8'"
    print('sql语句:',sql)

    3.执行sql语句,返回sql查询成功的记录数

    修改一条数据

    result = cursor.execute(sql,user)
    print('返回记录数:',result)

    一定记得commit

    conn.commit()

    关闭连接,游标和连接都要关闭

    cursor.close()
    conn.close()

    判断结果

    if result:
    print('ok')
    else:
    print('error')

    <br>
    
    ### 删
    ```python
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    #导入模块
    import pymysql
    
    #删除不需要执行这2个input了
    # user = input('请输入用户名:')
    # pwd = input('请输入密码:')
    
    # 1.连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', password='', db='db2', charset='utf8')
    
    # 2.创建游标
    cursor = conn.cursor()
    
    sql = "delete from userinfo  where id = '2'"
    print('sql语句:',sql)
    
    # 3.执行sql语句,返回sql查询成功的记录数
    #删除一条数据
    result = cursor.execute(sql)
    print('返回记录数:',result)
    
    #一定记得commit
    conn.commit()
    
    # 关闭连接,游标和连接都要关闭
    cursor.close()
    conn.close()
    
    #判断结果
    if result:
        print('ok')
    else:
        print('error')
    
    

    查有三种:fetchone()fetchall()fetchmany

    fetchone():获取下一行数据(第一次使用时是首行),返回值是一个元组

    #导入模块
    import pymysql
    
    # 1.连接
    conn = pymysql.connect(host='localhost', port=3306, user='root', password='', db='db2', charset='utf8')
    
    # 2.创建游标
    cursor = conn.cursor()
    
    sql = 'select * from userinfo'
    cursor.execute(sql)
    
    # 查询第一行的数据
    row = cursor.fetchone()
    print(row) # (1, 'helln', '123')
    
    # 查询第二行数据
    row = cursor.fetchone()
    print(row) # (6, 'sophia', '123')
    
    # 4.关闭游标
    cursor.close()
    
    # 5.关闭连接
    conn.close()
    
    

    在fetchone示例中,在获取行数据的时候,可以理解开始的时候,有一个行指针指着第一行的上方,获取一行,它就向下移动一行,所以当行指针到最后一行的时候,就不能再获取到行的内容,所以我们可以使用如下方法来移动行指针: ```python cursor.scroll(1,mode='relative') # 相对当前位置移动,整数向下移动,负数向上移动 cursor.scroll(2,mode='absolute') # 相对绝对位置移动 ```
    fetchall(): 获取所有数据,返回值是元组套元组 ```python #导入模块 import pymysql

    1.连接

    conn = pymysql.connect(host='localhost', port=3306, user='root', password='', db='db2', charset='utf8')

    2.创建游标

    cursor = conn.cursor()

    sql = 'select * from userinfo'
    cursor.execute(sql)

    获取所有的数据

    rows = cursor.fetchall()
    print(rows)

    4.关闭游标

    cursor.close()

    5.关闭连接

    conn.close()

    默认情况下,我们获取到的返回值是元组,只能看到每行的数据,却不知道每一列代表的是什么,这个时候可以使用以下方式来返回字典,每一行的数据都会生成一个字典:
    ```python
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)  #在实例化的时候,将属性cursor设置为pymysql.cursors.DictCursor
    
    
    

    fetchmany(): 获取多行记录,括号内的参数为获取的行数 ```python #导入模块 import pymysql

    1.连接

    conn = pymysql.connect(host='localhost', port=3306, user='root', password='', db='db2', charset='utf8')

    2.创建游标

    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)

    sql = 'select * from userinfo'
    cursor.execute(sql)

    获取2条数据

    rows = cursor.fetchmany(2)
    print(rows)

    4.关闭游标

    cursor.close()

    5.关闭连接

    conn.close()

  • 相关阅读:
    5.4、获取对象信息
    5.3、继承和多态
    JS基础-组成
    js定时器
    js 原型链,继承,闭包,内存,泄露
    flex 布局
    点击导出table表格
    图片利用 new Image()预加载原理 和懒加载的实现原理
    js控制style样式
    自定义指令的用法
  • 原文地址:https://www.cnblogs.com/zzliu/p/10662720.html
Copyright © 2011-2022 走看看