在web编程中,安全性是咱们都必须面临的一个问题,包括cookie伪造,xsrf攻击等。tornado做为一个web framework,在安全性方面也提供了不少功能,这里简单介绍一下。javascript
在web编程中,浏览器常常使用cookie来保存相关用户信息,用于与server交互,可是cookie有不少安全问题,譬如cookie伪造。cookie有不少方式被修改,javascript,flash,以及browser plugin等,因此首先须要保证cookie不被修改。html
tornado提供了secure cookie机制来保证cookie不被修改。tornado使用一个密钥用来给cookie进行签名,用来保证cookie只能被服务器修改。由于密钥只有tornado server知道,因此其它应用程序是没办法修改cookie的值。java
tornado使用set_secure_cookie和get_secure_cookie来设置和读取browser的cookie。使用secure cookie,只须要在tornado启动的时候设置cookie_secret就好了,以下:web
import tornado.web import tornado.httpserver import tornado.ioloop class MainHandler(tornado.web.RequestHandler): def get(self): count = self.get_secure_cookie('count') count = (int(count) + 1) if count else 1 self.set_secure_cookie('count', str(count)) self.write(str(count)) settings = { 'cookie_secret' : 'S6Bp2cVjSAGFXDZqyOh+hfn/fpBnaEzFh22IVmCsVJQ=' } application = tornado.web.Application([ (r"/", MainHandler), ], **settings) http_server = tornado.httpserver.HTTPServer(application) http_server.listen(8080) tornado.ioloop.IOLoop.instance().start()
cookie_secret的生成以下:编程
import base64 import uuid base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes)
为了防止cross-site scripting attack,tornado能够再设置cookie的时候增长httponly字段,这样该cookie就不可以被javascript读取。同时,为了更高的安全性,能够给cookie设置secure属性,这个跟先前讨论的set_secure_cookie不同,上面那个是对cookie进行加密签名,保证不被修改,而这个则是让browser经过ssl传输cookie。启用这些功能很简单,只须要在设置cookie的时候处理。浏览器
class MainHandler(tornado.web.RequestHandler): def get(self): self.set_cookie('count1', '1', httponly = True, secure = True) self.set_secure_cookie('count2', '2', httponly = True, secure = True)
上面介绍的方法虽然可以保证cookie的安全,可是仍是防止不了XSRF攻击。为了防止XSRF攻击,首先设计web服务的时候就须要考虑http method的side effects。按照restful的编程模型,get只能用来获取数据,post才会去修改数据,这样就能在很大的程度上面防止XSRF,由于对于一般状况来讲,XSRF攻击就是经过设置img的src为一个恶意的get请求,只要咱们的get不会进行数据修改,天然就能防止。安全
可是一些恶意的操做仍然可以发送post请求来进行攻击,譬如经过HTML forms或者XMLHTTPRequest API,因此为了防止post这种的攻击,咱们须要一些额外的机制。服务器
tornado提供了一个XSRF保护机制,原理很简单,就是在post提交数据的时候额外加入一个_xsrf字段,这个字段的值是从secure cookie里面获取的,由于其它的应用程序获取不到这个cookie的值,因此咱们可以保证post的安全性。开启xsrf protection也很简单。restful
settings = { 'cookie_secret' : 'S6Bp2cVjSAGFXDZqyOh+hfn/fpBnaEzFh22IVmCsVJQ=', 'xsrf_cookies' : True } application = tornado.web.Application([ (r"/", MainHandler), (r"/purchase", PurchaseHandler) ], **settings)
在post提交的form里面,咱们只须要设置以下:cookie
<form action="/purchase" method="POST"> {{ xsrf_form_html() }} <input type="submit" value="赞成" name="agree"/> </form>
tornado还提供了用户认证功能,当用户登陆以后,会将用户的相关信息保存到一个地方,一般是在cookie里面。当用户的cookie过时,再次访问web服务的时候就会被重定向到登录页面。
要实现上述功能,只须要重载get_current_user函数,配置login_url和使用authenticated decorator就好了。以下:
class BaseHandler(tornado.web.RequestHandler): def get_current_user(self): return self.get_secure_cookie('username') class LoginHandler(BaseHandler): def get(self): str = '''<body><form action="/login" method="POST"> UserName: <input type="text" name="username" /> <input type="submit" value="Login" /> </form></body>''' self.write(str) def post(self): self.set_secure_cookie('username', self.get_argument('username')) self.redirect('/') class MainHandler(BaseHandler): @tornado.web.authenticated def get(self): user = self.current_user self.write('hello ' + user) class LogoutHandler(BaseHandler): def get(self): self.clear_cookie('username') self.redirect('/') settings = { 'cookie_secret' : 'S6Bp2cVjSAGFXDZqyOh+hfn/fpBnaEzFh22IVmCsVJQ=', 'login_url' : '/login' } application = tornado.web.Application([ (r'/', MainHandler), (r'/login', LoginHandler), (r'/logout', LogoutHandler) ], **settings) http_server = tornado.httpserver.HTTPServer(application) http_server.listen(8080) tornado.ioloop.IOLoop.instance().start()
web安全一直是一个很是严重的问题,咱们在写代码的时候必定要注意,这里有一篇如何写安全web的Guide。tornado虽然提供了一些安全机制,可是仍然不能彻底保证绝对安全性,因此不少时候就须要咱们决定我所写的服务到底应该有什么样的安全级别,从在这个级别下面如何保证安全性就能够了。