登录验证流程
Topic sourcesha1和md5都是摘要算法,防篡改。我没注意到哪里用了md5,廖大手滑了。
2.关于cookie的一切信息都可以从客户端伪造。 在本实战项目中的cookie用来实现保持会话的效果。 假如登录模块或权限模块设计时欠考虑,机智的用户会通过伪造cookie的方式冒用其他用户甚至管理员的身份登陆系统。轻则搞个恶作剧,重则站长心血毁于一旦。
1.在用户登录成功后,服务端向客户端设置了一个名为awesession
的cookie,
cookie的内容为"用户id-cookie过期时间-【一封介绍信】"
,
我们开启上帝视角,得知介绍信里边的内容是一个由配方生成的字符串,配方如下:
SHA1(用户id- 用户口令- 过期时间-SecretKey盐值)
在本例中,服务端不保存介绍信的副本,只记住介绍信的制作配方。
这个配方向服务端保证,使用相同的原料总能得到相同的结果。
#介绍信制作配方
def user2cookie(user, max_age):
expires = str(int(time.time() + max_age))
s = '%s-%s-%s-%s' % (user.id, user.passwd, expires, _COOKIE_KEY) #配方登场
L = [user.id, expires, hashlib.sha1(s.encode('utf-8')).hexdigest()]
return '-'.join(L)
登陆流程:
- 客户端每次请求都会连同相应的cookie发送到服务端。
- 服务端抽出cookie中的用户id和过期时间。
- 再从数据库中抽出该用户的登陆密码按照原来的配方再次生成一封【新介绍信】。
- 然后和cookie带来的【旧介绍信】进行比较. 4.1 如果两封信的内容不一致,则证明客户伪造了登陆信息或者伪造了介绍信,总之他不太老实。对这样的刺儿头用户,我们要把它的浏览器重定向到登录页面。
async def cookie2user(cookie_str):
if not cookie_str:
return None
try:
L = cookie_str.split('-')
if len(L) != 3:
return None
uid, expires, sha1 = L #提取用户id,过期时间,介绍信
if int(expires) < time.time():
return None
user = await User.find(uid)
if user is None:
return None
s = '%s-%s-%s-%s' % (uid, user.passwd, expires, _COOKIE_KEY)#熟悉的配方
if sha1 != hashlib.sha1(s.encode('utf-8')).hexdigest():#比一比新旧两封介绍信
logging.info('invalid sha1')
return None
user.passwd = '******'
return user
except Exception as e:
logging.exception(e)
return None
以前我也纳闷儿,为什么用户登录的时候要把用户输入的密码先经过一次加密再和数据库中用户密码的密文比较?按人类的方式应该把数据库中用户的密文解密再直接和用户输入的密码明文比较才对呀。
那年csdn密码泄露事件后,我终于琢磨明白前人为什么要这样设计,真是充满了智慧。
- 1
改个鸡儿
看了三遍登录验证流程,还是很模糊。。。
“并与浏览器cookie中的MD5进行比较,如果相等,则说明用户已登录,否则,cookie就是伪造的。”
1,服务器每次都生成新的SHA1 和 第一次发送给客户端的SHA1相比较? 2,cookie的伪造,是伪造哪些部分?有什么用?