uname = input('请输入用户名:')pword = input('请输入密码:') sql = "select * from userinfo where username='%s' and password='%s';"%(uname,pword) print(sql) res = cursor.execute(sql) #res我们说是得到的行数,如果这个行数不为零,说明用户输入的用户名和密码存在,如果为0说名存在,你想想对不 print(res) #如果输入的用户名和密码错误,这个结果为0,如果正确,这个结果为1 if res: print('登陆成功') else: print('用户名和密码错误!') #运行看结果:居然登陆成功 请输入用户名:chao' -- xxx 请输入密码: select * from userinfo where username='chao' -- xxx' and password=''; 1 登陆成功 我们来分析一下: 此时uname这个变量等于什么,等于chao' -- xxx,然后我们来看我们的sql语句被这个字符串替换之后是个什么样子: select * from userinfo where username='chao' -- xxx' and password=''; 其中chao后面的这个',在进行字符串替换的时候,我们输入的是chao',这个引号和前面的引号组成了一对,然后后面--在sql语句里面是注释的意思,也就是说--后面的sql语句被注释掉了。也就是说,拿到的sql语句是select * from userinfo where username='chao';然后就去自己的数据库里面去执行了,发现能够找到对应的记录,因为有用户名为chao的记录,然后他就登陆成功了,但是其实他连密码都不知道,只知道个用户名。。。,他完美的跳过了你的认证环节。
然后我们再来看一个例子,直接连用户名和密码都不知道,但是依然能够登陆成功的情况:
请输入用户名:xxx' or 1=1 -- xxxxxx请输入密码:select * from userinfo where username='xxx' or 1=1 -- xxxxxx' and password=''; 3 登陆成功 我们只输入了一个xxx' 加or 加 1=1 加 -- 加任意字符串 看上面被执行的sql语句你就发现了,or 后面跟了一个永远为真的条件,那么即便是username对不上,但是or后面的条件是成立的,也能够登陆成功。
之前我们的sql语句是这样写的:sql = "select * from userinfo where username='%s' and password='%s';"%(uname,pword)以后再写的时候,sql语句里面的%s左右的引号去掉,并且语句后面的%(uname,pword)这些内容也不要自己写了,按照下面的方式写 sql = "select * from userinfo where username=%s and password=%s;" 难道我们不传值了吗,不是的,我们通过下面的形式,在excute里面写参数: #cursor.execute(sql,[uname,pword]) ,其实它本质也是帮你进行了字符串的替换,只不过它会将uname和pword里面的特殊字符给过滤掉。 看下面的例子: uname = input('请输入用户名:') #输入的内容是:chao' -- xxx或者xxx' or 1=1 -- xxxxx pword = input('请输入密码:') sql = "select * from userinfo where username=%s and password=%s;" print(sql) res = cursor.execute(sql,[uname,pword]) #res我们说是得到的行数,如果这个行数不为零,说明用户输入的用户名和密码存在,如果为0说名存在,你想想对不 print(res) #如果输入的用户名和密码错误,这个结果为0,如果正确,这个结果为1 if res: print('登陆成功') else: print('用户名和密码错误!') #看结果: 请输入用户名:xxx' or 1=1 -- xxxxx 请输入密码: select * from userinfo where username=%s and password=%s; 0 用户名和密码错误!
通过pymysql提供的excute完美的解决了问题。
总结咱们刚才说的两种sql注入的语句 #1、sql注入之:用户存在,绕过密码chao' -- 任意字符#2、sql注入之:用户不存在,绕过用户与密码 xxx' or 1=1 -- 任意字符
解决方法总结:
# 原来是我们对sql进行字符串拼接# sql="select * from userinfo where name='%s' and password='%s'" %(user,pwd)# print(sql) # res=cursor.execute(sql) #改写为(execute帮我们做字符串拼接,我们无需且一定不能再为%s加引号了) sql="select * from userinfo where name=%s and password=%s" #!!!注意%s需要去掉引号,因为pymysql会自动为我们加上 res=cursor.execute(sql,[user,pwd]) #pymysql模块自动帮我们解决sql注入的问题,只要我们按照pymysql的规矩来。
阅读目录
一 IDE工具介绍(Navicat)
生产环境还是推荐使用mysql命令行,但为了方便我们测试,可以使用IDE工具,我们使用Navicat工具,这个工具本质上就是一个socket客户端,可视化的连接mysql服务端的一个工具,并且他是图形界面版的。我们使用它和直接使用命令行的区别就类似linux和windows系统操作起来的一个区别。
Navicat的安装教程看这篇博客:
二 pymysql模块
我们要学的pymysql就是用来在python程序中如何操作mysql,它和mysql自带的那个客户端还有navicat是一样的,本质上就是一个套接字客户端,只不过这个套接字客户端是在python程序中用的,既然是客户端套接字,应该怎么用,是不是要连接服务端,并且和服务端进行通信啊,让我们来学习一下pymysql这个模块
一 链接、执行sql、关闭(游标)
fetchone:(1, '男', 1, '理解')
fetchone:(2, '女', 1, '钢蛋') fetchall:((3, '男', 1, '张三'), (4, '男', 1, '张一'))二 execute()之sql注入
之前我们进行用户名密码认证是先将用户名和密码保存到一个文件中,然后通过读文件里面的内容,来和客户端发送过来的用户名密码进行匹配,现在我们学了数据库,我们可以将这些用户数据保存到数据库中,然后通过数据库里面的数据来对客户端进行用户名和密码的认证。
自行创建一个用户信息表userinfo,里面包含两个字段,username和password,然后里面写两条记录
但是我们来看下面的操作,如果将在输入用户名的地方输入一个 chao'空格然后--空格然后加上任意的字符串,就能够登陆成功,也就是只知道用户名的情况下,他就能登陆成功的情况:
然后我们再来看一个例子,直接连用户名和密码都不知道,但是依然能够登陆成功的情况:
上面两个例子就是两个sql注入的问题,看完上面这两个例子,有没有感觉后背发凉啊同志们,别急,我们来解决一下这个问题,怎么解决呢?
有些网站直接在你输入内容的时候,是不是就给你限定了,你不能输入一些特殊的符号,因为有些特殊符号可以改变sql的执行逻辑,其实不光是--,还有一些其他的符号也能改变sql语句的执行逻辑,这个方案我们是在客户端给用户输入的地方进行限制,但是别人可不可以模拟你的客户端来发送请求,是可以的,他模拟一个客户端,不按照你的客户端的要求来,就发一些特殊字符,你的客户端是限制不了的。所以单纯的在客户端进行这个特殊字符的过滤是不能解决根本问题的,那怎么办?我们服务端也需要进行验证,可以通过正则来将客户端发送过来的内容进行特殊字符的匹配,如果有这些特殊字符,我们就让它登陆失败。
在服务端来解决sql注入的问题:不要自己来进行sql字符串的拼接了,pymysql能帮我们拼接,他能够防止sql注入,所以以后我们再写sql语句的时候按下面的方式写:
通过pymysql提供的excute完美的解决了问题。
解决方法总结:
三 增、删、改:conn.commit()
查操作在上面已经说完了,我们来看一下增删改,也要注意,sql语句不要自己拼接,交给excute来拼接
四 查:fetchone,fetchmany,fetchall
五 获取插入的最后一条数据的自增ID