数据库
- 概述:tornado没有自带的ORM , 对于数据库需要自己去适配
- 目前python3.6+tornado还没有比较完善的驱动
- 链接:
-
在应用启动时创建一个数据库链接实例,提供各个RequestHandler使用。
-
在RequestHandler中通过self.application来获取其应用
# application.py:创建数据库实例 self.db = SunckSql(config.mysql["host"],config.mysql["user"],config.mysql["passwd"], config.mysql["dbName"]) ------------------------------------- # index.py from sunckSql import SunckSql class studentsHandler(RequestHandler): def get(self): # 去数据据中提取数据 stus = self.application.db.get_all_obj("select * from tb_student","tb_student") self.render("student.html",stus=stus)
-
应用安全
-
Cookie
-
普通cookie(不安全)
-
设置
原型:self.set_cookie(name,value,domain=None,expires=None,path="/",expires_day=None,**kwags) 参数:name:cookie名, value:cookie值 domain:提交cookie时匹配的域名 path:提交COOKIE时匹配的路径 expirse:cookie的有效期,可以是时间戳、整数、时间元组、datatime类型,为UTC时间 expirse_days:cookie的有效期,天数,优先级低于expires ----------------------------------------------------------
-原理:设置cookie实际上是通过设置header的Set-Cookie来实现的
两中方法都可以设置cookie self.set_header("Set-Cookie","luciano=nice;Path=/") 推荐:self.set_cookie("luciano","computerGOD")
-
获取
原型:self.get_cookie(name,default=None) 参数: name: 要获取的 cookie名称 default:如果名为name 的cookie不存在,则返回default值
-
清除
-
作用:删除名为name ,并同时匹配domain 和 path的 cookie’
原型:self.clear_cookie(name,path="/",domain=None) self.clear_all_cookies(path="/",domain=None)
-
注意:执行清除cookie操作后并不是立即删除浏览器端的Cookie而是给cookie的值设置为空,
并改变其有限期限为失效。真正删除cookie是由浏览器自己去清理
-
-
-
安全cookie (加密)
-
django没有的Cookie
-
cookie是存在客户端浏览器的数据,很容易被篡改
-
tornado提供了一种对cookie进行简易的加密方式来防止cookie被而已篡改
-
设置:
-
需要为应用配置一个用来给cookie进行混肴的加密密钥
import base64 import uuid base64.b64encode(uuid.uuid4().bytes+uuid.uuid4().bytes) >>> 会生成一串字符串(100亿年不会出现重复) --------------------------------------- 将生成好的密钥配置到config.py "cookie_secret":"tfA8keUBRy2y+HdXA91DSSDVq3v3EUp6gbsGqeHUHTA=",
-
原型:
self.set_secure_cookie(name=,value=,expires_days=30,version=None,**kwargs)
-
作用:设置一个带有签名和时间戳的cookie,可以防止伪造
客户端获取到的cookie值:2|1:0|10:1593503769|5:quezi|8:V0ROTUQ=|f218bbb14c9c39bacf3ce303cbe48d61f112c04d3140a5b68d793dffcda9e3fe 说明:安全cookie的版本,默认是2版本,":"前面是位数,":"后面是相应位数对应的值, "0": 默认 “1593503769”:时间戳 “quezi”: cookieName "V0ROTUQ=": base64的编码的cookie值 “f218bbb14c9c39bacf3ce303cbe48d61f112c04d3140a5b68d793dffcda9e3fe”:签名值,不带长度说明
-
-
获取
-
原型:
self.get_secure_cookie(name=,value=,max_age_days=31,min_version=None) 参数: value: 如果cookie存在且验证通过,返回cookie值,否则返回None max_age_days:max_age_days(过滤安全cookie的时间戳) 不同于 expires(设置浏览器总cookie的有效时间) ,
-
-
注意:也不是完全的安全,一定程度上增加了破解cookie的难度
以后不要用cookie存储一些敏感性数据
-
-
-
XSRF
-
跨站请求伪造
当用户从浏览器上粘贴几个标签放到一个普通的html页面上去登录我们服务器的"cookie计数器"地址时,
在我们不知情,我们未授权的情况下,“cookie计数器”网站cookie被使用,以至于cookie计数器网址
认为是它自己网站调用了Handler逻辑黑客:html file:///C:/Users/Shinelon/Desktop/test.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <img src="http://127.0.0.1:8080/cookienum"> <h1>去看看吧 ,我可能把你弄坏</h1> </body> </html> ------------------------------------------ 服务器:index.py class cookienum(RequestHandler): def prepare(self): # 往往通过预处理函数来做cookie计数, pass def get(self,*args,**kwargs): # 获取cookie中 name 为 count的值,判断count的数量 # 如果没获取到那说明是第一次,即count=1 否则就是第“>1次”,则让count += 1 。 # 最后更新cookie中count值 count = self.get_cookie("count",None) if not count: count = 1 else: count = int(count) count += 1 self.set_cookie("count",str(count)) self.render("cookinum.html",count=count) ---------------------------------------------- 这样下来 只要黑客不断刷新他的html 网页,我们服务器就会不断的更新cookie name为count的值
-
上一个程序使用的时GET方式模拟攻击,为了防止这种攻击,一般对于相对安全的操作是不会放在GET请求中的,
一般会用做POST请求 -
XSRF保护:(同源策略)
同源:同协议 、 同域名 、 同端口
-
开启XSRF保护
config.py添加 "xsrf_cookies":True
-
应用:
-
模板 {% module xsrf_form_html() %}
在form表单上面加上: {% module xsrf_form_html() %} 作用: 1.为浏览器设置了_xsrf的安全cookie,这个cookie会在关闭浏览器失效 cookie:Set-Cookie: _xsrf=2|0a7a73bc|93954775aead64d33a14231bf4aeb0dd|1593510433; Path=/ 2.为模板表单添加了一个隐藏域,名为_xsrf,值为_xsrf这个cookie的值 隐藏域:<input type="hidden" name="_xsrf" value="2|0a7a73bc|93954775aead64d33a14231bf4aeb0dd|1593510433"> -----------------------------------------------------------------
-
注意:这这方式看似解决了跨站请求伪造,但是实际上依然未解决:
----------------------------------------------------------- 黑客: html file:///C:/Users/Shinelon/Desktop/test.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> # 将服务器上的代码隐藏于 copy到黑客本地的html中 <input type="hidden" name="_xsrf" value="2|0a7a73bc|93954775aead64d33a14231bf4aeb0dd|1593510433"> <img src="http://127.0.0.1:8080/cookienum"> <h1>去看看吧 ,我可能把你弄坏</h1> </body> </html> -------------------------------------------------------------- 服务器 index.py class postfile(RequestHandler): def get(self): self.render("postfile.html") def post(self,*args,**kwargs): count = self.get_cookie("count", None) if not count: count = 1 else: count = int(count) count += 1 self.set_cookie("count", str(count)) self.redirect("/cookienum") ------------------------------------------------------- 没有安全
-
非模板(三种方式)
-
手动设置 _xsrf的cookie
-
{% module xsrf_form_html() %} 这句话的内部原理:
手动创建<input>隐藏域 ,并设置name属性值为_xsrf,value属性值名为_xsrf的cookie值 -------------------------------------------- # 手动设置_xsrf 的 cookie class setxsrfcookie(RequestHandler): def get(self,*args,**kwargs): #设置一个_xsrf的cookie self.xsrf_token self.finish("ok") ----------------------------------------- html: <input id="hi" type="hidden" name="_xsrf" value=""> <script type="text/javascript"> function getCookie(name) { var cook = document.cookie.match("\\b"+name+"=([^;]*)\\b") //match() 查找 "\\b"二进制 return cook ? cook[1] : undefined // 三目运算符 ? } document.getElementById("hi").value = getCookie("_xsrf") console.log(getCookie("_xsrf"))
-
-
发起ajax请求
<button onclick="login()">登录</button> --------------------------------- // ajax POST: function login(){ console.log("_xsrf") // _xsrf = 值&username=值&passwd = 值 $.post("/postfilenew","_xsrf="+getCookie('_xsrf')+"&username="+"luciano"+"&passwd="+"1234",function (data) { console.log(data) alert("ok") }) } ------------------------------ // ajax原生:(推荐使用) function login(){ data = { "username":"lucinao", "passwd":"123", } // 将 data 对象转成 JSON字符串 dataStr = JSON.stringify(data) $.ajax({ url : "/postfilenew", method:"POST", data : dataStr, success:function () { alert("ok") }, // 设置请求头 headers:{ "X-XSRFToken":getCookie("_xsrf"), } }) }
-
问题:需要手动添加_xsrf的cookie,需要再进入主页时候自动设置上_xsrf的cookie
路由最下面加上: (r'/(.*)$',index.StaticFileHandler, {"path":os.path.join(config.BASE_DIRS,"static/html"),"default_filename":"index.html"}) ------------------------ index.py加上: class StaticFileHandler(tornado.web.StaticFileHandler): # 重写父类__init__方法 def __init__(self,*args,**kwargs): super(StaticFileHandler,self).__init__(*args,**kwargs) # 在父类中手动设置_xsrf 的 cookie self.xsrf_token
-
-
-