本文和大家分享的主要是tornado中cookie
驗(yàn)證機(jī)制相關(guān)內(nèi)容,一起來看看吧,希望對大家
學(xué)習(xí)tornado有所幫助。
處理過程簡單來說就是驗(yàn)證密碼之后服務(wù)器端(tornado)
返回帶有
cookie
信息的
Set-Cookie header
給客戶端
,
之后客戶端發(fā)起請求時(shí)會(huì)把此
cookie
放入
Cookie header
中發(fā)給服務(wù)器端。
tornado 設(shè)置 cookie
首先是對 cookie
的變量進(jìn)行設(shè)置
, Morsel
是含有幾個(gè)特殊
key
的類似于
dict
的對象
def
set_cookie(self, name, value, domain=None, expires=None, path="/", expires_days=None):
if
not hasattr(self, "_new_cookie"):
self._new_cookie = Cookie.SimpleCookie()
self._new_cookie[name] = value
morsel = self._new_cookie[name]
if domain:
morsel["domain"] = domain
if expires_days
is
not
None
and
not expires:
expires = datetime.datetime.utcnow() + datetime.timedelta(
days=expires_days)
if expires:
morsel["expires"] = httputil.format_timestamp(expires)
if path:
morsel["path"] = path
然后將 cookie
的
header flush
給客戶端
def
flush(self, include_footers=False, callback=None):
...
if hasattr(self, "_new_cookie"):
for cookie
in self._new_cookie.values():
self.add_header("Set-Cookie", cookie.OutputString(
None))
...
return self.request.connection.write_headers(
start_line, self._headers, chunk, callback=callback)
...
torando 讀取 cookie 并驗(yàn)證
tornado
從瀏覽器那獲取
cookie
則特別簡單,直接取出
header
中
Cookie
字段的內(nèi)容
,
然后解析一下
def
cookies(self):
if
not hasattr(self, "_cookies"):
self._cookies = Cookie.SimpleCookie()
if "Cookie"
in self.headers:
try:
parsed = parse_cookie(self.headers["Cookie"])
except Exception:
pass
else:
for k, v
in parsed.items():
try:
self._cookies[k] = v
except Exception:
pass
return self._cookies
以上代碼就是 cookie
在
server
和瀏覽器中傳遞的過程
.
當(dāng)然這只是簡單的傳遞
,
很容易找到規(guī)律并進(jìn)行暴力破解進(jìn)行提權(quán)攻擊
.
tornado
提供了加密的
cookie, cookie
的傳遞還是上述代碼
,
唯一的不同是在服務(wù)端對
cookie
的
value
進(jìn)行了加密
,
這樣用戶即使知道其他用戶的名字
,
也無法在短時(shí)間內(nèi)構(gòu)造出一條正確的
cookie
tornado
在服務(wù)端需要自己定義一個(gè)
secret key.
一個(gè)加密的
cookie
的
value
由
(value, timestamp, signature)
三元組組成
,
一般
value
可以通過加密算法構(gòu)造
,
而
timestamp
則直接可以從現(xiàn)有的
cookie
里面直接取
,
所以最重要的是
signature
的構(gòu)造
,
由于用戶不知道
secret.
所以用戶無法通過算法構(gòu)造出
signature,
只能竊取或者通過暴力破解
.
而 服務(wù)端則能夠通過
cookie
確認(rèn)
value
是正常的
value
且能夠取出
value
里包含的信息
加密代碼
def
create_signed_value(secret, name, value):
clock = time.time
timestamp = utf8(str(int(clock())))
value = base64.b64encode(utf8(value))
signature = _create_signature_v1(secret, name, value, timestamp)
value = b"|".join([value, timestamp, signature])
return value
def
_create_signature_v1(secret, *parts):
hash = hmac.new(utf8(secret), digestmod=hashlib.sha1)
for part
in parts:
hash.update(utf8(part))
return utf8(hash.hexdigest())
解密代碼
def
_decode_signed_value_v1(secret, name, value, max_age_days, clock):
parts = utf8(value).split(b"|")
signature = _create_signature_v1(secret, name, parts[0], parts[1])
if
not _time_independent_equals(parts[2], signature):
return
None
clock = time.time
timestamp = int(parts[1])
if timestamp < clock() - max_age_days * 86400:
gen_log.warning("Expired cookie %r", value)
return
None
return base64.b64decode(parts[0])
def
_time_independent_equals(a, b):
for x, y
in zip(a, b):
result |= ord(x) ^ ord(y)
return result == 0
總結(jié)
函數(shù) _time_independent_equals
是很講究的。 它總是花費(fèi)同樣的時(shí)間去比較用戶的輸入和你計(jì)算的結(jié)果。比如用戶想要暴力構(gòu)造一些
session,
如果比較函數(shù)花費(fèi)的時(shí)間和
signature
前面
n
字節(jié)是否正確正
(
或者負(fù)
)
相關(guān)。那么變更
signature,
通過大量查看延時(shí)
,
理論上是能把
signature
暴力破解出來的
,
而這個(gè)
_time_independent_equals
可以防止這種攻擊。
另外, tornado
這種校驗(yàn)
cookie
的方式能夠天然解決
cookie
一致性的問題,可以方面的進(jìn)行水平擴(kuò)展。
來源: nosa.me