标签:
	本文和大家分享的主要是tornado中cookie 验证机制相关内容,一起来看看吧,希望对大家 
学习tornado有所帮助。
	处理过程简单来说就是验证密码之后服务器端(tornado) 返回带有  cookie  信息的  Set-Cookie header 给客户端 ,  之后客户端发起请求时会把此  cookie  放入  Cookie header  中发给服务器端。
	tornado 设置 cookie
	首先是对 cookie  的变量进行设置 , Morsel  是含有几个特殊  key  的类似于  dict  的对象
	def  set_cookie(self, name, value, domain=None, expires=None, path="/", expires_days=None):
	if  not hasattr(self, "_new_cookie"):
	self._new_cookie = Cookie.SimpleCookie()
	self._new_cookie[name] = value
	morsel = self._new_cookie[name]
	if domain:
	morsel["domain"] = domain
	if expires_days  is  not  None  and  not expires:
	expires = datetime.datetime.utcnow() + datetime.timedelta(
	days=expires_days)
	if expires:
	morsel["expires"] = httputil.format_times**p(expires)
	if path:
	morsel["path"] = path
	然后将 cookie  的  header flush  给客户端
	def  flush(self, include_footers=False, callback=None):
	...
	if hasattr(self, "_new_cookie"):
	for cookie  in self._new_cookie.values():
	self.add_header("Set-Cookie", cookie.OutputString( None))
	...
	return self.request.connection.write_headers(
	start_line, self._headers, chunk, callback=callback)
	...
	torando 读取 cookie 并验证
	tornado  从浏览器那获取  cookie  则特别简单,直接取出  header  中  Cookie  字段的内容 ,  然后解析一下
	def  cookies(self):
	if  not hasattr(self, "_cookies"):
	self._cookies = Cookie.SimpleCookie()
	if "Cookie"  in self.headers:
	try:
	parsed = parse_cookie(self.headers["Cookie"])
	except Exception:
	pass
	else:
	for k, v  in parsed.items():
	try:
	self._cookies[k] = v
	except Exception:
	pass
	return self._cookies
	以上代码就是 cookie  在  server  和浏览器中传递的过程 . 当然这只是简单的传递 ,  很容易找到规律并进行暴力**进行提权攻击 .
	tornado  提供了加密的  cookie, cookie  的传递还是上述代码 ,  唯一的不同是在服务端对  cookie  的 value  进行了加密 ,  这样用户即使知道其他用户的名字 ,  也无法在短时间内构造出一条正确的  cookie
	tornado  在服务端需要自己定义一个  secret key.  一个加密的  cookie  的  value  由 (value, times**p, signature)  三元组组成 ,  一般  value 可以通过加密算法构造 ,  而  times**p  则直接可以从现有的  cookie  里面直接取 ,  所以最重要的是  signature  的构造 ,  由于用户不知道 secret. 所以用户无法通过算法构造出  signature,  只能窃取或者通过暴力** . 而 服务端则能够通过  cookie  确认  value  是正常的  value  且能够取出  value  里包含的信息
	加密代码
	def  create_signed_value(secret, name, value):
	clock = time.time
	times**p = utf8(str(int(clock())))
	value = base64.b64encode(utf8(value))
	signature = _create_signature_v1(secret, name, value, times**p)
	value = b"|".join([value, times**p, signature])
	return value
	def  _create_signature_v1(secret, *parts):
	hash = hmac.new(utf8(secret), digestmod=hashlib.sha1)
	for part  in parts:
	hash.update(utf8(part))
	return utf8(hash.hexdigest())
	解密代码
	def  _decode_signed_value_v1(secret, name, value, max_age_days, clock):
	parts = utf8(value).split(b"|")
	signature = _create_signature_v1(secret, name, parts[0], parts[1])
	if  not _time_independent_equals(parts[2], signature):
	return  None
	clock = time.time
	times**p = int(parts[1])
	if times**p < clock() - max_age_days * 86400:
	gen_log.warning("Expired cookie %r", value)
	return  None
	return base64.b64decode(parts[0])
	def  _time_independent_equals(a, b):
	for x, y  in zip(a, b):
	result |= ord(x) ^ ord(y)
	return result == 0
	总结
	函数 _time_independent_equals  是很讲究的。 它总是花费同样的时间去比较用户的输入和你计算的结果。比如用户想要暴力构造一些  session,  如果比较函数花费的时间和  signature  前面  n  字节是否正确正 ( 或者负 ) 相关。那么变更 signature,  通过大量查看延时 ,  理论上是能把  signature  暴力**出来的 , 而这个  _time_independent_equals  可以防止这种攻击。
	另外, tornado  这种校验  cookie  的方式能够天然解决  cookie  一致性的问题,可以方面的进行水平扩展。
	来源: nosa.me
	
Python程序员必知的tornado模板引擎语法
标签: