zoukankan      html  css  js  c++  java
  • MySQL 之Navicat Premium 12安装使用、pymysql模块使用、sql注入问题的产生与解决

    本文内容提要:

    1. Navicat Premium 12 的介绍、使用。

    2. pymysql模块的使用

    3. sql注入问题的产生与解决

    ----------------------------------------------------------------------------------------------------------------------------------------

    一、Navicat Premium 12简介与使用:

           /1、Navicat Premium 12是一套快速、可靠并价格相宜的数据库管理工具,专为简化数据库的管理及降低系统管理成本而设。它的设计符合数据库管理员、开发人员及中小企业的需要。Navicat 是以直觉化的图形用户界面而建的,让你可以以安全并且简单的方式创建、组织、访问并共用信息。

      其实Navicat Premium 12与MySQL直接的关系就相当于pycharm与python解释器之间的关系,而Navicat就是一种操作数据库图形化的一种功能加强软件。学会它的目的只有一个:更高效地让我们操作管理查询数据库

      2、Navicat Premium 12的使用:(由于Navicat Premium 12主要是图形化操作界面,所以个人此处省去操作流程,具体流程都可以通过可视化的图形界面自己去摸索清楚,这是作为程序员的最基本的要求吧。)

      Navicat Premium 12安装与破解方法详见:https://www.cnblogs.com/suguangti/p/10875870.html

      对Navicat Premium 12的使用我们需要掌握大致以下几种:

    1. 测试+连接数据库
    2. 新建数据库
    3. 新建表,新增字段+类型+约束
    4. 设计表:外键
    5. 新建查询
    6. 读懂并会建立表模型

        # Tip:批量加注释:Ctrl+?  批量去注释:Ctrl+shift+?

    二、pymysql模块的使用:

    pymysql的一般使用方法:import pymysql # 导入pymysql模块

    查:

    # 与数据库建立连接
    conn = pymysql.connect(
        host='localhost',
        user='root',
        password='******',
        database='pymysql_ts',
        charset='utf8'
    )
    
    # 建立游标连接
    # cursor = conn.cursor()   # 执行完毕返回的结果,默认用元组显示
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)  # 以字典的方式显示数据
    
    # pymysql 操作数据库的方法:
    # 执行sql语句
    # ----------------------------------------------------------------------------------------------
    下面是pymysql_ts数据库下的user_info表内容:
    # id name password # 1 sgt 123456 # 2 jason 123456 # 3 smoke 123456 # ---------------------------------------------------------------------------------------------- # 1、验证登陆账户密码: ''' while True: user = input('>>>>:').strip() pwd = input('>>>>:').strip() sql = "select * from user_info where name ='%s' and password ='%s'" % (user, pwd) # 这里的%s需要加引号 # sql = 'select * from user_info' # 这里的%s需要加引号 res = cursor.execute(sql) # 执行sql语句,返回sql查询成功的记录 if res: # sql查询语句中的where条件能匹配到name和password字段,返回查询记录1,打印登陆成功后的信息 print('登陆成功') # 获取真实数据(该用户名在数据库中的记录数据) else: print('用户名密码错误') # where条件匹配不到数据,查询数据为空,则账号密码错误 ''' # ---------------------------------------------------------------------------------------------- sql = "select * from user_info" # sql语句,获取user_info表的所有记录 cursor.execute(sql) # 获取真实数据之前一定要执行sql语句 # ---------------------------------------------------------------------------------------------- # fetchall() 返回一个包含多个字典的列表 ''' print(cursor.fetchall()) # 获取满足where条件能查询到的所有真实数据 # 打印结果:[{'id': 1, 'name': 'sgt', 'password': '123456'}, # {'id': 2, 'name': 'jason', 'password': '123456'}, {'id': 3, 'name': 'smoke', 'password': '123456'}] ''' # ---------------------------------------------------------------------------------------------- # fetchone() 返回一个字典 ''' print(cursor.fetchone()) # 打印结果:{'id': 1, 'name': 'sgt', 'password': '123456'} print(cursor.fetchone()) # 打印结果:{'id': 2, 'name': 'jason', 'password': '123456'} print(cursor.fetchone()) # 打印结果:{'id': 3, 'name': 'smoke', 'password': '123456'} ''' # 注意看结果,第一个id为1,后面依次是2、3,也就是说第二次获取结果是在第一次获取结果之后开始获取的,这就和前面的cursor的 # 意思不谋而合,游标连接,也就是每次获取真实数据都是按游标位置开始获取,类似于管道取值,取完一个少一个。 # 需求:如果我想每次获取数据都从最一开始获取数据,该如何实现? # 解决方法:相对移动,绝对移动 ''' # 相对移动: # cursor.scroll(1,'relative') # 数字1代表从当前位置移动一个记录位置 # 比如: print(cursor.fetchone()) # 打印结果:{'id': 1, 'name': 'sgt', 'password': '123456'} cursor.scroll(1,'relative') # 第1个记录位置已经获取完,从当前记录位置2开头向后移动1个记录位置,则下次打印就是从第3个记录位置的开头开始获取 print(cursor.fetchone()) # 打印结果:{'id': 3, 'name': 'smoke', 'password': '123456'} ''' ''' # 绝对移动: # cursor.scroll(1,'absolute') # 从最开头的记录位置开始数的第1个位置后也就是第2个记录位置开头开始获取数据 print(cursor.fetchone()) # 打印结果:{'id': 1, 'name': 'sgt', 'password': '123456'} print(cursor.fetchone()) # 打印结果:{{'id': 2, 'name': 'jason', 'password': '123456'} print(cursor.fetchone()) # 打印结果:{'id': 3, 'name': 'smoke', 'password': '123456'} # 运行到此处全部记录全部取完 print(cursor.fetchone()) # 打印结果:None cursor.scroll(0, 'absolute') # 游标移动到在绝对位置(最开始),0代表最开始,如果是1代表0位置向后推一个记录位置 print(cursor.fetchone()) # 打印结果:{'id': 1, 'name': 'sgt', 'password': '123456'} ''' # ---------------------------------------------------------------------------------------------- # fetchmany(n) 指定取n个记录,返回一个n个字典数据的列表,不写n默认为1 # print(cursor.fetchmany()) # 获取满足where条件能查询到的n条真实数据,用一个包含n个字典的列表表示 # ''' print(cursor.fetchmany()) # 打印结果:[{'id': 1, 'name': 'sgt', 'password': '123456'}] # ''' cursor.close() # 关闭游标连接 conn.close() # 断开数据库连接

    增删改

    # -------------------------------------------------------------------------------------------------------------
    # pymysql的增删改:
    # 其实就是用sursor.execute(sql)去执行sql语句,不同的就是sql语句是什么
    # 先导入模块:
    import pymysql
    # 建立数据库连接:
    conn = pymysql.connect(
        host='localhost',
        user='root',
        password='******',
        database='pymysql_ts',
        charset='utf8'
    )
    # 这里还列出该数据库下的表user_info内容:
    # id   name     password
    # 1    sgt       123456
    # 2    jason     123456
    # 3    smoke     123456
    # 建立游标连接(设置返回结果为字典模式)
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 开始写入sql数据操作语句:
    '''
    user = input('输入注册用户名:').strip()
    pwd = input('输入注册密码:').strip()
    '''
    # 还记得sql的注入导致的安全问题吗?这里不管是数据库的增删改查都要用上面的解决方法
    # 方法为:sql语句字符串里面先写上不带引号的%s,传入值在cursor.execute()中传入。
    # -----------------------------------------------------------------------------------
    # 增(表中增加记录用insert)
    '''
    sql = "insert into user_info(name,password) values (%s,%s)"
    # 执行sql语句:
    cursor.execute(sql, (user, pwd))
    # 走到这里执行execute实际是并没有真正的修改数据库,接下来需要将修改行为和结果提交到数据库才能修改生效:
    conn.commit()
    '''
    # 此时打开Navicat软件,刷新下后,就能看到user_info表中新增了一条记录
    # 结果:
    # 输入注册用户名:hello
    # 输入注册密码:666888
    # 1    sgt      123456
    # 2    jason    123456
    # 3    smoke    123456
    # 4    hello    666888
    # -----------------------------------------------------------------------------------
    # 改(表中增加记录用update)
    '''
    sql = "update user_info set name=%s where id=4"
    cursor.execute(sql, 'world')
    conn.commit()
    '''
    # 结果:(打开Navicat软件查看,需要刷新一下)
    # 1    sgt        123456
    # 2    jason    123456
    # 3    smoke    123456
    # 4    world    666888
    # -----------------------------------------------------------------------------------
    # 一次新增多行记录的方法:cursor.executemany(sql,[(),(),()])
    sql = "insert into user_info(name,password) values (%s,%s)"   # 插入多条,此处还是写一个(%s,%s)
    cursor.executemany(sql, [('abc', '123'), ('def', '123'), ('ghi', '123')])
    conn.commit()
    # 结果:
    # 1    sgt      123456
    # 2    jason    123456
    # 3    smoke    123456
    # 4    world    666888
    # 5    abc      123
    # 6    def      123
    # 7    ghi      123

    三、sql注入问题产生与解决方法:

    # ----------------------------------------------------------------------------------------------
    # 接下来来个sql注入引发的安全问题:
    # 通过上的验证用户名密码进行登录的过程,我们可以分析出,通过pymysql连接数据库后后,实际上还是运用sql语句来操作数据库,
    # 获取数据库中的记录,比如通过where条件语句来拿用户输入的name和password与数据库表中的对应字段记录进行查询,注意
    # 这里是查询,看能否查询到用户输入的name和password的对应字段记录,如果有,就返回个记录个数,或者获取到该记录信息,
    # 如果查询不到,就返回空,至此查询完毕。
    # 所以细心的人就会发现一个bug,或者安全问题
    # 我们仔细看看sql查询语句:sql = "select * from user_info where name='%s' and password='%s'" % (user,pwd)
    # 这里如果在第一个%s做点手脚比如输入:xxx' or 1=1 -- dfafdafafaf
    # 看不懂? 来分析下:我们知道在mysql里面--代表注释,也就是--后面的都是注释,无语句执行效果。这样就省去了密码验证,同时
    # 前面xxx',这里有个单引号,为何有个单引号,我把第一个%s放进sql语句中:
    # sql = "select * from user_info where name='xxx' or 1=1 -- dfafdafafaf' and password='%s'" % (user,pwd)
    #                                            ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
    # 看到没有,这个select查询语句变成什么样了?  select * from user_info where name='xxx' or 1=1
    # 此时我们就看到上面语句结果,最后结果就是where条件1=1成立,表user_info中的全部数据都能被查询到。
    # -------------------------------------------------------------------------------------------------------------
    # 来一段具体代码:
    # 首先在数据库pymysql_ts中有个表:
    # id  name     password
    # 1   sgt       123456
    # 2   jason     123456
    # 3   smoke     123456
    
    import pymysql
    # 建立数据库连接:
    conn = pymysql.connect(
        host='localhost',
        user='root',
        password='******',
        database='pymysql_ts',  # 找到其中一个数据库
        charset='utf8'
    )
    # 以返回结果为字典的形式建立游标连接:
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 开始操作数据库:
    user = input('输入用户名:').strip()
    pwd = input('输入密码:').strip()
    # 写sql语句:
    '''
    sql = "select * from user_info where name='%s' and password='%s'" % (user, pwd)
    # 执行sql语句,返回查询的记录数
    cursor.execute(sql)
    # 打印获取的查询记录:
    print(cursor.fetchall())
    # 结果为:
    # 输入用户名:ddd' or 1=1 -- dfadfafafafa
    # 输入密码:
    # [{'id': 1, 'name': 'sgt', 'password': '123456'}, {'id': 2, 'name': 'jason', 'password': '123456'}, 
    # {'id': 3, 'name': 'smoke', 'password': '123456'}]
    # 至此,这就是sql注入问题,很显然这是不安全的,也是不对的*_*,需要解决啊!
    '''
    # -------------------------------------------------------------------------------------------------------------
    # 解决方法:将用户输入的数据交给mysql去处理
    # 在写sql语句时候进行变化一下:
    sql = "select * from user_info where name=%s and password=%s"
    cursor.execute(sql, (user, pwd))   # 去掉上面%s的引号,将user和pwd传入execute里面,pymysql会自动识别%s自行传入数据
    print(cursor.fetchall())
    # 结果:
    # 输入用户名:xxx' or 1=1 -- dafafafafafa
    # 输入密码:fdaf
    # ()
    # 最后总结:为安全考虑,最好不要手动去拼接查询sql语句。
    cursor.close()  #  当然最后养成好习惯关闭打开的游标连接
    conn.close()    #  同时断开的连接的数据库
  • 相关阅读:
    如何在iTerm2中配置oh my zsh?
    sublime中格式化jsx文件
    ES6 new syntax of Literal
    ES6 new syntax of Rest and Spread Operators
    How to preview html file in our browser at sublime text?
    ES6 new syntax of Default Function Parameters
    ES6 new syntax of Arrow Function
    七牛云2018春招笔试题
    Spring-使用注解开发(十二)
    Spring-声明式事物(十一)
  • 原文地址:https://www.cnblogs.com/suguangti/p/10875897.html
Copyright © 2011-2022 走看看