1、基本操作

Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)

在后台设置cookie:

  1. class IndexHanlder(tornado.web.RequestHandler):
  2. def get(self):
  3. print(self.cookies) #获取http请求中携带的浏览器中的所有cookie
  4. print(self.get_cookie("k1")) # 获取浏览器中的cooki
  5. self.set_cookie("k1","v1") #为浏览器设置cookie

在前端(浏览器上使用JavaScript):

  1. document.cookie #获取浏览器中所有的cookie
  2. document.cookie.split(";") #获取浏览器中具体某一个cookie,需要先分割,再操作
  3. document.cookie = "k1=999" #设置cookie

由于Cookie保存在浏览器端,所以在浏览器端也可以使用JavaScript来操作Cookie:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <h1>123</h1>
  9. </body>
  10. <script>
  11. /*设置cookie,指定秒数过期*/
  12. function setCookieBySeconds(name,value,expires){
  13. var current_date = new Date(); //获取当前时间
  14. current_date.setSeconds(current_date.getSeconds() + expires);
  15. document.cookie = name + "= "+ value +";expires=" + current_date.toUTCString();
  16. }
  17. /*设置cookie,指定天数过期*/
  18. function setCookieByDays(name,value,expires){
  19. var current_date = new Date(); //获取当前时间
  20. current_date.setDate(current_date.getDate() + expires);
  21. document.cookie = name + "= "+ value +";expires=" + current_date.toUTCString();
  22. }
  23. </script>
  24. </html>

2、加密cookie(签名)

Cookie 很容易被恶意的客户端伪造。加入你想在 cookie 中保存当前登陆用户的 id 之类的信息,你需要对 cookie 作签名以防止伪造。Tornado 通过 set_secure_cookie 和 get_secure_cookie 方法直接支持了这种功能。 要使用这些方法,你需要在创建应用时提供一个密钥,名字为 cookie_secret。 你可以把它作为一个关键词参数传入应用的设置中:

  1. def _create_signature_v1(secret, *parts):
  2. hash = hmac.new(utf8(secret), digestmod=hashlib.sha1)
  3. for part in parts:
  4. hash.update(utf8(part))
  5. return utf8(hash.hexdigest())
  6.  
  7. # 加密
  8. def _create_signature_v2(secret, s):
  9. hash = hmac.new(utf8(secret), digestmod=hashlib.sha256)
  10. hash.update(utf8(s))
  11. return utf8(hash.hexdigest())
  12.  
  13. def create_signed_value(secret, name, value, version=None, clock=None,
  14. key_version=None):
  15. if version is None:
  16. version = DEFAULT_SIGNED_VALUE_VERSION
  17. if clock is None:
  18. clock = time.time
  19.  
  20. timestamp = utf8(str(int(clock())))
  21. value = base64.b64encode(utf8(value))
  22. if version == 1:
  23. signature = _create_signature_v1(secret, name, value, timestamp)
  24. value = b"|".join([value, timestamp, signature])
  25. return value
  26. elif version == 2:
  27. # The v2 format consists of a version number and a series of
  28. # length-prefixed fields "%d:%s", the last of which is a
  29. # signature, all separated by pipes. All numbers are in
  30. # decimal format with no leading zeros. The signature is an
  31. # HMAC-SHA256 of the whole string up to that point, including
  32. # the final pipe.
  33. #
  34. # The fields are:
  35. # - format version (i.e. 2; no length prefix)
  36. # - key version (integer, default is 0)
  37. # - timestamp (integer seconds since epoch)
  38. # - name (not encoded; assumed to be ~alphanumeric)
  39. # - value (base64-encoded)
  40. # - signature (hex-encoded; no length prefix)
  41. def format_field(s):
  42. return utf8("%d:" % len(s)) + utf8(s)
  43. to_sign = b"|".join([
  44. b"",
  45. format_field(str(key_version or 0)),
  46. format_field(timestamp),
  47. format_field(name),
  48. format_field(value),
  49. b''])
  50.  
  51. if isinstance(secret, dict):
  52. assert key_version is not None, 'Key version must be set when sign key dict is used'
  53. assert version >= 2, 'Version must be at least 2 for key version support'
  54. secret = secret[key_version]
  55.  
  56. signature = _create_signature_v2(secret, to_sign)
  57. return to_sign + signature
  58. else:
  59. raise ValueError("Unsupported version %d" % version)
  60.  
  61. # 解密
  62. def _decode_signed_value_v1(secret, name, value, max_age_days, clock):
  63. parts = utf8(value).split(b"|")
  64. if len(parts) != 3:
  65. return None
  66. signature = _create_signature_v1(secret, name, parts[0], parts[1])
  67. if not _time_independent_equals(parts[2], signature):
  68. gen_log.warning("Invalid cookie signature %r", value)
  69. return None
  70. timestamp = int(parts[1])
  71. if timestamp < clock() - max_age_days * 86400:
  72. gen_log.warning("Expired cookie %r", value)
  73. return None
  74. if timestamp > clock() + 31 * 86400:
  75. # _cookie_signature does not hash a delimiter between the
  76. # parts of the cookie, so an attacker could transfer trailing
  77. # digits from the payload to the timestamp without altering the
  78. # signature. For backwards compatibility, sanity-check timestamp
  79. # here instead of modifying _cookie_signature.
  80. gen_log.warning("Cookie timestamp in future; possible tampering %r",
  81. value)
  82. return None
  83. if parts[1].startswith(b""):
  84. gen_log.warning("Tampered cookie %r", value)
  85. return None
  86. try:
  87. return base64.b64decode(parts[0])
  88. except Exception:
  89. return None
  90.  
  91. def _decode_fields_v2(value):
  92. def _consume_field(s):
  93. length, _, rest = s.partition(b':')
  94. n = int(length)
  95. field_value = rest[:n]
  96. # In python 3, indexing bytes returns small integers; we must
  97. # use a slice to get a byte string as in python 2.
  98. if rest[n:n + 1] != b'|':
  99. raise ValueError("malformed v2 signed value field")
  100. rest = rest[n + 1:]
  101. return field_value, rest
  102.  
  103. rest = value[2:] # remove version number
  104. key_version, rest = _consume_field(rest)
  105. timestamp, rest = _consume_field(rest)
  106. name_field, rest = _consume_field(rest)
  107. value_field, passed_sig = _consume_field(rest)
  108. return int(key_version), timestamp, name_field, value_field, passed_sig
  109.  
  110. def _decode_signed_value_v2(secret, name, value, max_age_days, clock):
  111. try:
  112. key_version, timestamp, name_field, value_field, passed_sig = _decode_fields_v2(value)
  113. except ValueError:
  114. return None
  115. signed_string = value[:-len(passed_sig)]
  116.  
  117. if isinstance(secret, dict):
  118. try:
  119. secret = secret[key_version]
  120. except KeyError:
  121. return None
  122.  
  123. expected_sig = _create_signature_v2(secret, signed_string)
  124. if not _time_independent_equals(passed_sig, expected_sig):
  125. return None
  126. if name_field != utf8(name):
  127. return None
  128. timestamp = int(timestamp)
  129. if timestamp < clock() - max_age_days * 86400:
  130. # The signature has expired.
  131. return None
  132. try:
  133. return base64.b64decode(value_field)
  134. except Exception:
  135. return None
  136.  
  137. def get_signature_key_version(value):
  138. value = utf8(value)
  139. version = _get_version(value)
  140. if version < 2:
  141. return None
  142. try:
  143. key_version, _, _, _, _ = _decode_fields_v2(value)
  144. except ValueError:
  145. return None
  146.  
  147. return key_version

五、Session(依赖于cookie)

由于cookie中需要保存客户的很多信息,而且如果信息很多的话,服务端与客户端交互的时候也浪费流量,所以我们需要用很少的一段字符串来保存很多的信息,这就是我们所要引进的session。

cookie 和session 的区别:

1、cookie数据存放在客户的浏览器上,session数据放在服务器上。

2、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗    考虑到安全应当使用session。

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

4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

5、所以个人建议:    将登陆信息等重要信息存放为SESSION    其他信息如果需要保留,可以放在COOKIE中

 (1)利用session实现用户验证

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. import tornado.web
  4. import tornado.ioloop
  5. import hashlib
  6. import time
  7. li = {}
  8. class IndexHanlder(tornado.web.RequestHandler):
  9. def get(self):
  10. obj = hashlib.md5()
  11. obj.update(bytes(str(time.time()),encoding="utf-8"))
  12. random_str = obj.hexdigest()
  13. li[random_str]={}
  14. li[random_str]["k1"]=123
  15. li[random_str]["k2"]=456
  16. li[random_str]["is_login"]=True
  17. self.set_cookie("qqqqqq",random_str)
  18. self.write("成功设置cookie")
  19. def post(self, *args, **kwargs):
  20. pass
  21.  
  22. class ManagerHanlder(tornado.web.RequestHandler):
  23. def get(self):
  24. random_str = self.get_cookie("qqqqqq",None)
  25. current_user_info = li.get(random_str,None)
  26. if not current_user_info:
  27. self.redirect("/index")
  28. else:
  29. if li[random_str]["is_login"]:
  30. self.write("欢迎")
  31. else:
  32. self.redirect("/index")
  33. def post(self, *args, **kwargs):
  34. pass
  35.  
  36. settings={
  37. "template_path":"tpl",
  38. "static_path":"st",
  39. "cookie_secret":"123"
  40. }
  41.  
  42. class IndeHanlder(tornado.web.RequestHandler):
  43. def get(self):
  44. self.render("1.html")
  45. application = tornado.web.Application([
  46. (r"/index", IndexHanlder),
  47. (r"/manager", ManagerHanlder),
  48. ],**settings)
  49.  
  50. if __name__ == "__main__":
  51. application.listen(8888)
  52. tornado.ioloop.IOLoop.instance().start()

 (2)利用session验证用户精简版

  1. #!/usr/bin/env/python
  2. # -*- coding:utf-8 -*-
  3. import tornado.web
  4.  
  5. container = {}
  6. # container = {
  7. # # "第一个人的随机字符串":{},
  8. # # "第一个人的随机字符串":{'k1': 111, 'parents': '你'},
  9. # }
  10.  
  11. class Session:
  12. def __init__(self, handler):
  13. self.handler = handler
  14. self.random_str = None
  15.  
  16. def __genarate_random_str(self):
  17. import hashlib
  18. import time
  19. obj = hashlib.md5()
  20. obj.update(bytes(str(time.time()), encoding='utf-8'))
  21. random_str = obj.hexdigest()
  22. return random_str
  23.  
  24. def __setitem__(self, key, value):
  25. # 在container中加入随机字符串
  26. # 定义专属于自己的数据
  27. # 在客户端中写入随机字符串
  28. # 判断,请求的用户是否已有随机字符串
  29. if not self.random_str:
  30. random_str = self.handler.get_cookie('__kakaka__')
  31. if not random_str:
  32. random_str = self.__genarate_random_str()
  33. container[random_str] = {}
  34. else:
  35. # 客户端有随机字符串
  36. if random_str in container.keys():
  37. pass
  38. else:
  39. random_str = self.__genarate_random_str()
  40. container[random_str] = {}
  41. self.random_str = random_str
  42.  
  43. container[self.random_str][key] = value
  44. self.handler.set_cookie("__kakaka__", self.random_str)
  45.  
  46. def __getitem__(self, key):
  47. # 获取客户端的随机字符串
  48. # 从container中获取专属于我的数据
  49. # 专属信息【key】
  50. random_str = self.handler.get_cookie("__kakaka__")
  51. if not random_str:
  52. return None
  53. # 客户端有随机字符串
  54. user_info_dict = container.get(random_str,None)
  55. if not user_info_dict:
  56. return None
  57. value = user_info_dict.get(key, None)
  58. return value
  59. class BaseHandler(tornado.web.RequestHandler):
  60. def initialize(self):
  61. self.session = Session(self)
  62. class IndexHandler(BaseHandler):
  63. def get(self):
  64. if self.get_argument('u',None) in ['alex','eric']:
  65. self.session['is_login'] = True
  66. self.session['name'] =self.get_argument('u',None)
  67. print(container)
  68. else:
  69. self.write('请你先登录')
  70. class MangerHandler(BaseHandler):
  71. def get(self):
  72. val = self.session['is_login']
  73. if val:
  74. self.write(self.session['name'])
  75. else:
  76. self.write('登录失败')
  77. class LoginHandler(BaseHandler):
  78. def get(self,*args,**kwargs):
  79. self.render('login.html',status="")
  80. def post(self, *args, **kwargs):
  81. user = self.get_argument('user',None)
  82. pwd = self.get_argument('pwd',None)
  83. code = self.get_argument('code',None)
  84. check_code = self.session['CheckCode']
  85. if code.upper() == check_code.upper():
  86. self.write('验证码正确')
  87. else:
  88. self.render('login.html',status ='验证码错误')
  89. class CheckCodeHandler(BaseHandler):
  90. def get(self,*args,**kwargs):
  91. import io
  92. import check_code
  93. mstream = io.BytesIO()
  94. img, code = check_code.create_validate_code()
  95. img.save(mstream,'GIF')
  96. self.session['CheckCode']=code
  97. self.write(mstream.getvalue())
  98. class CsrfHandler(BaseHandler):
  99. def get(self,*args,**kwargs):
  100. self.render("csrf.html")
  101. def post(self, *args, **kwargs):
  102. self.write("hahahahaah")
  103.  
  104. settings = {
  105. 'template_path':'views',
  106. 'static_path':'static',
  107. "xsrf_cookies":True
  108. }
  109. application = tornado.web.Application([
  110. (r'/index',IndexHandler),
  111. (r'/manger',MangerHandler),
  112. (r'/login',LoginHandler),
  113. (r'/check_code',CheckCodeHandler),
  114. (r'/csrf',CsrfHandler),
  115. ],**settings)
  116.  
  117. if __name__ == "__main__":
  118. application.listen(8888)
  119. tornado.ioloop.IOLoop.instance().start()

  

 

cookie的更多相关文章

  1. 超大 Cookie 拒绝服务攻击

    有没有想过,如果网站的 Cookie 特别多特别大,会发生什么情况? 不多说,马上来试验一下: for (i = 0; i < 20; i++) document.cookie = i + '= ...

  2. IE10、IE11 User-Agent 导致的 ASP.Net 网站无法写入Cookie 问题

    你是否遇到过当使用一个涉及到Cookie操作的网站或者管理系统时,IE 6.7.8.9下都跑的好好的,唯独到了IE10.11这些高版本浏览器就不行了?好吧,这个问题码农连续2天内遇到了2次.那么,我们 ...

  3. 解决cookie跨域访问

    一.前言 随着项目模块越来越多,很多模块现在都是独立部署.模块之间的交流有时可能会通过cookie来完成.比如说门户和应用,分别部署在不同的机器或者web容器中,假如用户登陆之后会在浏览器客户端写入c ...

  4. jquery插件的用法之cookie 插件

    一.使用cookie 插件 插件官方网站下载地址:http://plugins.jquery.com/cookie/ cookie 插件的用法比较简单,直接粘贴下面代码示例: //生成一个cookie ...

  5. 一个诡异的COOKIE问题

    今天下午,发现本地的测试环境突然跑不动了,thinkphp直接跑到异常页面,按照正常的排错思路,直接看thinkphp的log 有一条 [ error ] [2]setcookie() expects ...

  6. [转载]Cookie/Session的机制与安全

    Cookie和Session是为了在无状态的HTTP协议之上维护会话状态,使得服务器可以知道当前是和哪个客户在打交道.本文来详细讨论Cookie和Session的实现机制,以及其中涉及的安全问题. 因 ...

  7. jquery.cookie的使用

    今天想到了要为自己的影像日记增加赞的功能,并且需要用到cookie. 记得原生的js操作cookie也不是很麻烦的,但似乎jquery更简单,不过相比原生js,需要额外引入2个文件,似乎又不是很好,但 ...

  8. 跨域问题,前端主动向后台发送cookie

    跨域是什么? 从一个域名的网页访问另一个域名的资源,就会出现跨域.只要协议.端口.域名有一个不同就会出现跨域 例如: 1.协议不同  http://www.baidu.com:80 和 https:/ ...

  9. 【流量劫持】沉默中的狂怒 —— Cookie 大喷发

    精简版:http://www.cnblogs.com/index-html/p/mitm-cookie-crack.html 前言 上一篇文章 讲解了如何借助前端技术,打造一个比 SSLStrip 更 ...

  10. 好好了解一下Cookie

    Cookie的诞生 由于HTTP协议是无状态的,而服务器端的业务必须是要有状态的.Cookie诞生的最初目的是为了存储web中的状态信息,以方便服务器端使用.比如判断用户是否是第一次访问网站.目前最新 ...

随机推荐

  1. [连载]《C#通讯(串口和网络)框架的设计与实现》- 8.总体控制器的设计

    目       录 第八章           总体控制器的设计... 2 8.1           总控制器的职能... 2 8.2           组装和释放部件... 3 8.3      ...

  2. spider RPC高级特性

    多租户 spider原生支持多租户部署,spider报文头对外开放了机构号.系统号两个属性用于支持多租户场景下的路由. 多租户场景下的路由可以支持下述几种模式: n  系统号: n  系统号+服务号( ...

  3. HTML5 oninput实时监听输入框值变化的完美方案

    在网页开发中经常会碰到需要动态监听输入框值变化的情况,如果使用 onkeydown.onkeypress.onkeyup 这个几个键盘事件来监测的话,监听不了右键的复制.剪贴和粘贴这些操作,处理组合快 ...

  4. Unicode简介

    计算机只能处理二进制,因此需要把文字表示为二进制才能被计算机理解和识别. 一般的做法是为每一个字母或汉字分配一个id,然后用二进制表示这个id,存在内存或磁盘中.计算机可以根据二进制数据知道这个id是 ...

  5. 批处理bat 命令

    1.批处理常用符号: - echo 打开回显或关闭请求回显功能,或显示消息.如果没有任何参数,echo 命令将显示当前回显设置 语法:@echo [{ on|off }]  echo{"显示 ...

  6. PostgreSQL隐藏字段tableoid

    问题来源: 今天群里有人问:tableoid字段在每行都有,而且一个表里面的值是重复的,这样不合理...... 因此做了一些分析: 1)创建了一个表 apple=# \d test_time Tabl ...

  7. 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题

    调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...

  8. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

    什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...

  9. PHP语法(一):基础和变量

    相关链接: PHP语法(一):基础和变量 PHP语法(二):数据类型.运算符和函数 PHP语法(三):控制结构(For循环/If/Switch/While) 最近有个H5项目的需求,需要服务端,考察过 ...

  10. 使用parted给大于2T的磁盘分区

    1.使用命令parted /dev/sdb [root@server ~]# parted /dev/sdb GNU Parted 2.1 使用 /dev/sdb Welcome to GNU Par ...