python自动化测试学习笔记-6redis应用

上次我们学到了redis的一些操作,下面来实际运用以下。

这里我们先来学习一下什么是cookie和session。

什么是Cookie

其实简单的说就是当用户通过http协议访问一个服务器的时候,这个服务器会将一些Name/Value键值对返回给客户端浏览器,并将这些数据加上一些限制条件。在条件符合时,这个用户下次再访问服务器的时候,数据又被完整的带给服务器。

因为http是一种无状态协议,用户首次访问web站点的时候,服务器对用户一无所知。而Cookie就像是服务器给每个来访问的用户贴的标签,而这些标签就是对来访问的客户端的独有的身份的一个标识,这里就如同每个人的身份证一样,带着你的个人信息。而当一个客户端第一次连接过来的时候,服务端就会给他打一个标签,这里就如同给你发了一个身份证,当你下次带着这个身份证来的时候,服务器就知道你是谁了。所以Cookie是存在客户端的,这里其实就是在你的浏览器中。

Cookie中包含了一个由名字=值(name=value)这样的信息构成的任意列表,通过Set-Cookie或Set-Cookie2HTTP响应(扩展)首部将其贴到客户端身上。

Cookie的分类

这里Cookie主要分为两种:

会话Cookie:不设置过期时间,保存在浏览器的内存中,关闭浏览器,Cookie便被销毁

普通Cookie:设置了过期时间,保存在硬盘上

关于Session

上面我们知道了Cookie可以让服务器端跟踪每个客户端的访问,但是每次客户端的访问都必须传回这些Cookie,如果Cookie很多,这无形地增加了客户端与服务端的数据传输量,而Session的出现正是为了解决这个问题。

同一个客户端每次和服务端交互时,不需要每次都传回所有的Cookie值,而是只要传回一个ID这个ID是客户端第一次访问服务器的时候生成的,而且每个客户端是唯一的。这样每个客户端就有了一个唯一的ID,客户端只要传回这个ID就行了,这个ID通常是NANE为JSESIONID的一个Cookie。所以Session其实是利用Cookie进行信息处理的。

cookie和session的共同之处在于:cookie和session都是用来跟踪浏览器用户身份的会话方式。

cookie和session的区别是:cookie数据保存在客户端,session数据保存在服务器端。

cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,如果主要考虑到安全应当使用session,当然也没有绝对的安全,只是相对cookie,session更加安全

session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,如果主要考虑到减轻服务器性能方面,应当使用COOKIE

cookie和session各有优缺点,所以将登陆信息等重要信息存放为SESSION;其他信息如果需要保留,可以放在COOKIE中。

实例:

先来验证用session登录的程序,分析:

首先先设计一个登录的程序,生成session写入redis,然后设计一个查询程序,传入session进行校验。

    第一次登录:从my_user表中验证用户是否存在,用户存在且密码正确的场合生成session(规则:(当前时间戳+username))存入redis。

    第二次登录查看:

#1、先验证用户是否登陆,username,session
#2、验证session是否正确,判断和redis里边是否一致
#3、如果一致返回查询结果
#4、如果不一致,提示session非法
# session不存在,则提示用户未登录
# session不一致,登陆失败
#在K-V中传入session

以下是常用工具,放在lib目录的tools文件中:

#常用工具
import pymysql,hashlib,time
import redis
from conf import setting
#

#def op_mysql(host,user,passwd,db,sql,port=3306,charset='utf8'):
def op_mysql(sql):
conn=pymysql.connect(host=setting.MYSQL_HOST,user=setting.USER,passwd=setting.PASSWORD,port=setting.PORT,db=setting.DB,charset='utf8')
cur=conn.cursor(cursor=pymysql.cursors.DictCursor)
cur.execute(sql)
sql_start=sql[:6].upper()
if sql_start=='SELECT':#取sql的前6位,判断它是什么类型的语句。
res=cur.fetchall()
else:
conn.commit()
#res='ok'
cur.close()
conn.close()
return res
def op_redis(k,v=None,expired=0,db=0):
#def op_redis(host,passwd,k,v=None,port=6379,db=1):
#r=redis.Redis(host=host,password=passwd,port=port,db=db)
r=redis.Redis(host=setting.REDIS_HOST,password=setting.REDIS_PASSWORD,port=setting.REDIS_PORT,db=db)

if v:
r.setex(k,v,expired)
res='ok'
else:
#res=r.get(k).decode()#获取不到的时候返回none,none不能直接进行decode操作
res=r.get(k)
if res:
res=res.decode()
else:
res='none'
return res


def md5_password(st:str):#规定传参的类型必须是str类型
#st = hashlib.md5()
bytes_st=st.encode()
m=hashlib.md5(bytes_st)
return m.hexdigest()

 

#main.py

import flask,time,hashlib
from lib.tools import op_mysql,op_redis,md5_password
import json
server=flask.Flask(__name__)
@server.route('/login',methods=['post'])
def login():
username=flask.request.values.get('name','')
password=flask.request.values.get('passwd','')
sql="select * from my_user where username='%s';"%(username)
if username and password:
if op_mysql(sql):
print(op_mysql(sql))
if password==op_mysql(sql)[0]['passwd']:
session=md5_password(str(time.time())+username)
op_redis('session:%s'%username,session,expired=6000,db=2)
response={'code':200,'msg':'登陆成功','session':session}
else:
response={'code':101,'msg':'密码不正确'}
else:
response={'code':102,'msg':'用户不存在'}
else:
response={'code':103,'msg':'用户名或密码不能为空'}
return json.dumps(response,ensure_ascii=False)

启动服务后,在postman中调用127.0.0.1:8088/login?name=pei&passwd=123456,执行一个正确的用户登录,:

{"msg": "登陆成功", "code": 200, "session": "28b14dea0c7a668650fbb19f6364f482"}

查看到redis里边已经插入了一个session数据:

 

下面进行第二部,传入用户名、session,如果验证正确则查询中表中的数据:

@server.route('/getall',methods=['post','get'])
def getall():
username=flask.request.values.get('name')
session=flask.request.values.get('session')
k='session:%s'%(username)
redis_session=op_redis(k,db=2)
if username and session:
if redis_session:
if redis_session==session:

sql="select red,blue from seq "
response = op_mysql(sql)
else:
response={'code':101,'msg':'session非法'}
else:
response={'code':102,'msg':'未登录'}
else:
response={'code':103,'msg':'必填参数为空'}
return json.dumps(response,ensure_ascii=False)

以上是在k-v参数中传入session值,如需需要在cookie中传入session,代码如下:

就是把session=flask.request.values.get('session')改为session=flask.request.cookies.get('session')则取值就是在cookie中进行取值了。


@server.route('/getall_cookie',methods=['post','get'])
def getall_cookie():
username=flask.request.values.get('name')
session=flask.request.cookies.get('session')
k='session:%s'%(username)
redis_session=op_redis(k,db=2)
if username and session:
if redis_session:
if redis_session==session:

sql="select red,blue from seq "
response = op_mysql(sql)
else:
response={'code':101,'msg':'session非法'}
else:
response={'code':102,'msg':'未登录'}
else:
response={'code':103,'msg':'必填参数为空'}
return json.dumps(response,ensure_ascii=False)

在我们登录购物网站的话,如果勾选记住密码,一般情况下就是在客户端浏览器上添加了cookie,这样用户打开网站后后台会自动校验cookie信息,不用每次都传一次,如下是设置cookie的代码:

要在页面添加cookie需要先response=flask.make_response(),然后response.set_cookie('session',session)set上要添加的cookie信息

@server.route('/login_setcookie',methods=['post'])
def login_setcookie():
username=flask.request.values.get('name','')
password=flask.request.values.get('passwd','')
sql="select * from my_user where username='%s';"%(username)
if username and password:
if op_mysql(sql):
print(op_mysql(sql))
if password==op_mysql(sql)[0]['passwd']:
session=md5_password(str(time.time())+username)
op_redis('session:%s'%username,session,expired=6000,db=2)
response=flask.make_response()
response.set_cookie('session',session)
msg={'code':200,'msg':'登陆成功','session':session}
else:
msg={'code':101,'msg':'密码不正确'}
else:
msg={'code':102,'msg':'用户不存在'}
else:
msg={'code':103,'msg':'必填参数为空'}
return response

添加cookie后,我们在调用getall_cookie时只传入name,就能直接获取到seq表中的数据了。

 

补充:

mysql注入原理

上述代码中存在的sql语句如下:

sql="select * from my_user where username='%s';"%(username)

在获取username时,由于存在‘’,所以存在漏洞;

我们知道‘1’=‘1’是恒为真的,我们可以通过‘’,来模拟制造出这种恒等式,使sql在执行时跳过一些校验,从而进阶访问系统。

当我们输入name=“' or '1'='1”

我们将上述name的值带入sql如下:

sql="select * from my_user where username='' or '1'='1';"

我们在sqlyog中my_user表中执行这个语句,查询出了所有的用户信息,

 

在一些查询操作中,很容易产生漏洞,造成信息的泄露。

还有一种注入方式是:username="' show tabales ; --"

sql="select * from my_user where username='' show tabales ; --';"

sql语句中--表示注释掉后边的语句,这样就查询出了所有的表,可以对数据库随意进行操作。

为了防止sql的注入,在编写sql的时候我们尽量避免使用‘’,写成如下方式:

sql="select * from my_user where username=%s;",username

这样在传参的时候,可以直接传到输入的参数进行取值,例如:

def op_mysql_new(sql,*data):#第一个是位置参数,第二个是可变参数
cur.execute(sql,data)
#data是一个元祖,*data获取出所有传过去的参数
print(cur.fetchall())
sql="select * from users where name=%s and passwd=%s;"
name='pei'
passwd='123456'
op_mysql_new(sql,name,passwd)

###################################################33

传参:
def test(a,b):
print(a,b)

li=[1,2]
test(*li)#一个星代表把list里边的数据穿进去
d={'a':'123','b':'456'}
test(**d)#两个星代表从字典里边的数据传进去

 

posted @ 2018-01-29 18:58  yingfeipei  阅读(1337)  评论(0编辑  收藏  举报