在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雖然提供了一些安全機制,可是仍然不能徹底保證絕對安全性,因此不少時候就須要咱們決定我所寫的服務到底應該有什麼樣的安全級別,從在這個級別下面如何保證安全性就能夠了。