Cookie

Cookie

對於RequestHandler,除了在第二章中講到的之外,還提供了操作cookie的方法。

設置

set_cookie(name, value, domain=None, expires=None, path='/', expires_days=None)

參數說明:

參數名 說明
name cookie名
value cookie值
domain 提交cookie時匹配的域名
path 提交cookie時匹配的路徑
expires cookie的有效期,可以是時間戳整數、時間元組或者datetime類型,爲UTC時間
expires_days cookie的有效期,天數,優先級低於expires
import datetime

class IndexHandler(RequestHandler):
    def get(self):
        self.set_cookie("n1", "v1")
        self.set_cookie("n2", "v2", path="/new", expires=time.strptime("2016-11-11 23:59:59","%Y-%m-%d %H:%M:%S"))
        self.set_cookie("n3", "v3", expires_days=20)
        # 利用time.mktime將本地時間轉換爲UTC標準時間
        self.set_cookie("n4", "v4", expires=time.mktime(time.strptime("2016-11-11 23:59:59","%Y-%m-%d %H:%M:%S")))
        self.write("OK")

原理

設置cookie實際就是通過設置header的Set-Cookie來實現的。

class IndexHandler(RequestHandler):
    def get(self):
        self.set_header("Set-Cookie", "n5=v5; expires=Fri, 11 Nov 2016 15:59:59 GMT; Path=/") 
        self.write("OK")

獲取

get_cookie(name, default=None)

獲取名爲name的cookie,可以設置默認值。

class IndexHandler(RequestHandler):
    def get(self):
        n3 = self.get_cookie("n3")
        self.write(n3)

清除

clear_cookie(name, path='/', domain=None)

刪除名爲name,並同時匹配domain和path的cookie。

clear_all_cookies(path='/', domain=None)

刪除同時匹配domain和path的所有cookie。


class ClearOneCookieHandler(RequestHandler):
    def get(self):
        self.clear_cookie("n3")
        self.write("OK")

class ClearAllCookieHandler(RequestHandler):
    def get(self):
        self.clear_all_cookies()
        self.write("OK")

注意:執行清除cookie操作後,並不是立即刪除了瀏覽器中的cookie,而是給cookie值置空,並改變其有效期使其失效。真正的刪除cookie是由瀏覽器去清理的。

安全Cookie

Cookie是存儲在客戶端瀏覽器中的,很容易被篡改。Tornado提供了一種對Cookie進行簡易加密簽名的方法來防止Cookie被惡意篡改。

使用安全Cookie需要爲應用配置一個用來給Cookie進行混淆的祕鑰cookie_secret,將其傳遞給Application的構造函數。我們可以使用如下方法來生成一個隨機字符串作爲cookie_secret的值。

>>> import base64, uuid
>>> base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes)
'2hcicVu+TqShDpfsjMWQLZ0Mkq5NPEWSk9fi0zsSt3A='

Base64是一種基於64個可打印字符來表示二進制數據的表示方法。由於2的6次方等於64,所以每6個比特爲一個單元,對應某個可打印字符。三個字節有24個比特,對應於4個Base64單元,即3個字節需要用4個可打印字符來表示。

uuid, 通用唯一識別碼(英語:Universally Unique Identifier,簡稱UUID),是由一組32個16進制數字所構成(兩個16進制數是一個字節,總共16字節),因此UUID理論上的總數爲16^32=2^128,約等於3.4 x 10^38。也就是說若每納秒產生1兆個UUID,要花100億年纔會將所有UUID用完。

uuid模塊的uuid4()函數可以隨機產生一個uuid碼,bytes屬性將此uuid碼作爲16字節字符串。

將生成的cookie_secret傳入Application構造函數:

app = tornado.web.Application(
    [(r"/", IndexHandler),],
    cookie_secret = "2hcicVu+TqShDpfsjMWQLZ0Mkq5NPEWSk9fi0zsSt3A="
)

獲取和設置

set_secure_cookie(name, value, expires_days=30)

設置一個帶簽名和時間戳的cookie,防止cookie被僞造。

get_secure_cookie(name, value=None, max_age_days=31)

如果cookie存在且驗證通過,返回cookie的值,否則返回None。max_age_day不同於expires_days,expires_days是設置瀏覽器中cookie的有效期,而max_age_day是過濾安全cookie的時間戳。

class IndexHandler(RequestHandler):
    def get(self):
        cookie = self.get_secure_cookie("count")
        count = int(cookie) + 1 if cookie else 1
        self.set_secure_cookie("count", str(count))
        self.write(
            '<html><head><title>Cookie計數器</title></head>'
            '<body><h1>您已訪問本頁%d次。</h1>' % count + 
            '</body></html>'
        )




我們看簽名後的cookie值:

"2|1:0|10:1476412069|5:count|4:NQ==|cb5fc1d4434971de6abf87270ac33381c686e4ec8c6f7e62130a0f8cbe5b7609"

字段說明:

  1. 安全cookie的版本,默認使用版本2,不帶長度說明前綴
  2. 默認爲0
  3. 時間戳
  4. cookie名
  5. base64編碼的cookie值
  6. 簽名值,不帶長度說明前綴

注意:Tornado的安全cookie只是一定程度的安全,僅僅是增加了惡意修改的難度。Tornado的安全cookies仍然容易被竊聽,而cookie值是簽名不是加密,攻擊者能夠讀取已存儲的cookie值,並且可以傳輸他們的數據到任意服務器,或者通過發送沒有修改的數據給應用僞造請求。因此,避免在瀏覽器cookie中存儲敏感的用戶數據是非常重要的。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章