首先要理解一个概念

MAC (message authenticate code)

消息认证码(带密钥的Hash函数):密码学中,通信实体双方使用的一种验证机制,保证消息数据完整性的一种工具。

构造方法由M.Bellare提出,安全性依赖于Hash函数,故也称带密钥的Hash函数。消息认证码是基于密钥和消息摘要所获得的一个值,

可用于数据源发认证和完整性校验。

消息认证码(带密钥的Hash函数):密码学中,通信实体双方使用的一种验证机制,保证消息数据完整性的一种工具。

构造方法由M.Bellare提出,安全性依赖于Hash函数,故也称带密钥的Hash函数。消息认证码是基于密钥和消息摘要所获得的一个值,可用于数据源发认证和完整性校验。

在发送数据之前,发送方首先使用通信双方协商好的散列函数计算其摘要值。在双方共享的会话密钥作用下,由摘要值获得消息验证码。之后,它和数据一起被发送。接收方收到报文后,首先利用会话密钥还原摘要值,同时利用散列函数在本地计算所收到数据的摘要值,并将这两个数据进行比对。若两者相等,则报文通过认证。

签名cookie就是基于这种原理。

一般发送的数据都会做base64编码,关于base64编码可以看这个链接

blog.xiayf.cn/2016/01/24/base64-encoding/

总的来说:base64并不是用来加密的,base64是一种数据编码方式,目的让数据符合传输协议的要求,将二进制的数据转化为一种文本数据

在Python中提供了两个模块,去实现。以下是base64的基本用法

>>> import base64
>>> s='b'asdafsdafa'
SyntaxError: invalid syntax
>>> s=b'asdasdas'
>>> s_64 = base64.bencode(s) s_64 = base64.bencode(s)
AttributeError: module 'base64' has no attribute 'bencode'
>>> s_64 = base64.b64encode(s)
>>> s_64
b'YXNkYXNkYXM='
>>> base64.b64decode(s_64)
b'asdasdas'
>>>

对于mac,Python有个模块hmac基本用法如下

>>> import hmac
>>> hmac.new(b'slat')
<hmac.HMAC object at 0x0000000004110B70>
>>> hmac = hmac.new(b'slat')
>>> hmac.update(b'asdas')
>>> hmac.digest()
b'\xe8\\\xb6\x11\x9dj\rY\x06I\x1f[\x06\xeb\xeb\xf3'
>>>

文档说明

class HMAC(builtins.object)
| RFC 2104 HMAC class. Also complies with RFC 4231.
|
| This supports the API for Cryptographic Hash Functions (PEP 247).
|
| Methods defined here:
|
| __init__(self, key, msg=None, digestmod=None)
| Create a new HMAC object.
|
| key: key for the keyed hash object.
| msg: Initial input for the hash, if provided.
| digestmod: A module supporting PEP 247. *OR*
| A hashlib constructor returning a new hash object. *OR*
| A hash name suitable for hashlib.new().
| Defaults to hashlib.md5.
| Implicit default to hashlib.md5 is deprecated and will be
| removed in Python 3.6.
|
| Note: key and msg must be a bytes or bytearray objects.
|
| copy(self)
| Return a separate copy of this hashing object.
|
| An update to this copy won't affect the original object.
|
| digest(self)
| Return the hash value of this hashing object.
|
| This returns a string containing 8-bit data. The object is
| not altered in any way by this function; you can continue
| updating the object after calling this function.
|
| hexdigest(self)
| Like digest(), but returns a string of hexadecimal digits instead.
|
| update(self, msg)
| Update this hashing object with the string msg.

立即了基础,来看bottle框架设置签名cookie和获取签名cookie的值的源码.

设置签名cookie

first_bottle.py
response.set_cookie('account',username,secret='salt')
    def set_cookie(self, name, value, secret=None, **options):

        if not self._cookies:
self._cookies = SimpleCookie() if secret:
value = touni(cookie_encode((name, value), secret))
elif not isinstance(value, basestring):
raise TypeError('Secret key missing for non-string Cookie.') if len(value) > 4096: raise ValueError('Cookie value to long.')
self._cookies[name] = value for key, value in options.items():
if key == 'max_age':
if isinstance(value, timedelta):
value = value.seconds + value.days * 24 * 3600
if key == 'expires':
if isinstance(value, (datedate, datetime)):
value = value.timetuple()
elif isinstance(value, (int, float)):
value = time.gmtime(value)
value = time.strftime("%a, %d %b %Y %H:%M:%S GMT", value)
self._cookies[name][key.replace('_', '-')] = value

self._cookie默认是None,SimpleCookie继承BaseCookie,BaseCookie继承一个字典,所以暂且认为self.cookie是一个字典,

if secret  是判断,如果设置了密钥,就执行这一步,

def tob(s, enc='utf8'):
return s.encode(enc) if isinstance(s, unicode) else bytes(s)
def touni(s, enc='utf8', err='strict'):
return s.decode(enc, err) if isinstance(s, bytes) else unicode(s)
tonat = touni if py3k else tob

touni 函数是返回str类型的字符串,这里unicode=str,unicode(s) 相当于str(s)

def cookie_encode(data, key):
''' Encode and sign a pickle-able object. Return a (byte) string '''
msg = base64.b64encode(pickle.dumps(data, -1))
sig = base64.b64encode(hmac.new(tob(key), msg).digest())
return tob('!') + sig + tob('?') + msg

pickle.dumps将数据序列化,返回的是bytes类型的字符串,然后编码为base64    sig 是先用hmac加密,

最后将msg(消息) 和sig(签名)拼接,这样一个签名cookie就设置好了,注意这里的msg是一个(name,value)包含cookie的key和value

这样一个签名cookie就设置好了

理解了签名cookie的设置,再看获得签名cookie的值就比较简单了。。

大致原理是拿到cookie的值,通过?分割出message 和sig  ,再拿message和secret 进行hmac 拿到新的sig,这个新的sig与分割出来的sig比较,如果一致,表示没有被篡改,这样吧message 用base64decode

然后pickle.loads 就拿到原来的数组了。数组的[1]就是那个value,

def cookie_decode(data, key):
''' Verify and decode an encoded string. Return an object or None.'''
data = tob(data)
if cookie_is_encoded(data):
sig, msg = data.split(tob('?'), 1)if _lscmp(sig[1:], base64.b64encode(hmac.new(tob(key), msg).digest())):
return pickle.loads(base64.b64decode(msg))

因为之前setcookie时在自古穿前面加了一个感叹 号!  ,所以切片sig[1:]

def _lscmp(a, b):
''' Compares two strings in a cryptographically safe way:
Runtime is not affected by length of common prefix. '''
return not sum(0 if x==y else 1 for x, y in zip(a, b)) and len(a) == len(b)

上面这个函数是逐个字符比较,如果比较的字符都相等那么就返回0,否则返回1,这样如果是两个字符串完全匹配,就都是0,调用sum() 相加肯定返回0 ,否则肯定不是1,但是必须在长度相等的条件下才可以

测试代码
>>> a='asdas'
>>> unicode(a)
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
unicode(a)
NameError: name 'unicode' is not defined
>>> b='asd'
>>> (0 if x==y else 1 for x,y in zip(a,b))
<generator object <genexpr> at 0x0000000003170200>
>>> sum((0 if x==y else 1 for x,y in zip(a,b)))
0
>>> s=zip(a,b)
>>> s
<zip object at 0x0000000003147948>
>>> for i in s:
print(i) ('a', 'a')
('s', 's')
('d', 'd')

为什么比较字符串相等不直接用 a==b?

于洋 回到顶部

关于bottle WEB框架中签名cookie的一点理解的更多相关文章

  1. Python的Django框架中的Cookie相关处理

    Python的Django框架中的Cookie相关处理 浏览器的开发人员在非常早的时候就已经意识到. HTTP's 的无状态会对Web开发人员带来非常大的问题,于是(cookies)应运而生. coo ...

  2. 在 node.js 的 express web 框架中自动注册路由

    该方法主要是动态注册自己写的 router . 注册器 router 文件名为 loader.js  . var express = require('express'); var fs = requ ...

  3. 浅谈python web框架中的orm设计

    看了一下廖雪峰的那个web框架,其实就是封装了web.py,请求使用异步并将aiomysql做为MySQL数据库提供了异步IO的驱动,前端部分则整合了jinja.其中最难的应该是orm部分了. 下面是 ...

  4. 蜗牛历险记(二) Web框架(中)

    上篇简单介绍了框架所使用的Autofac,采用Autofac提供的Ioc管理整个Web项目中所有对象的生命周期,实现框架面向接口编程.接下来介绍框架的日志系统. 一.介绍之前 框架日志是否有存在的必要 ...

  5. Java Web servlet中的cookie

    点击submit后: 点击查看Cookies: 在C:\Documents and Settings\Administrator\Cookies目录下面会有一个     hongten@webproj ...

  6. 正确理解web交互中的cookie与session

    cookie存储在客户端的纯文本文件 用户请求服务器脚本 脚本设置cookie内容 并 通过http-response发送cookie内容到客户端并保存在客户端本地 客户端再次发送http请求的时候会 ...

  7. Bootstrap框架中的字形图标的理解

    最近项目中准备使用 Bootstrap 框架,看中了Ace Admin 这套皮肤,看其代码的时候,发现使用了字形图标.下面内容来源于网络,根据自己对新知识的学习曲线重新整合了一下: 一,字形图标的定义 ...

  8. 对web应用中单一入口模式的理解及php实现

    在我们web应用的开发中,经常会听见或看见单一入口模式,在我开始学习tp框架的时候也不理解为什么要运用一个单一入口模式,只是会使用,最近自己在搞一个小东西的时候才明白为什么在web开发中要运用单一入口 ...

  9. 关于css中层叠性的一点理解

    关于css层叠性的一点理解 标签(空格分隔): html css 我们平时在写css的时候会遇到这样的情况 <!DOCTYPE html> <html lang="en&q ...

随机推荐

  1. 访谈:BugPhobia’s Brief Communication

    0x01 :采访的学长简介 If you weeped for the missing sunset, you would miss all the shining stars 梁野,北京航空航天大学 ...

  2. Scrum Meeting NO.9

    Scrum Meeting No.9 1.会议内容 2.任务清单 徐越 序号 近期的任务 进行中 已完成 1 代码重构:前端通讯模块改为HttpClient+Json √ 2 "我" ...

  3. 《Linux内核分析》实践4

    <Linux内核分析> 实践四--ELF文件格式分析 20135211李行之 一.概述 1.ELF全称Executable and Linkable Format,可执行连接格式,ELF格 ...

  4. Linux内核分析— —进程的切换和系统的一般执行过程

    进程调度的时机 linux进程调度是基于分时和优先级的 中断处理过程(包括时钟中断.I/O中断.系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用s ...

  5. Linux内核分析——字符集总结与分析

      一.  设置修改系统.应用默认字符集 1. 查看虚拟机的字符集: 由此可见,该虚拟机的字符集为zh_CN.UTF-8. 2. 查看服务器支持的编码方式 3. 修改字符集类型 上图可见,LANG字符 ...

  6. ChangeSetenceSort(java)

    package com.home.test;       import java.util.Arrays;       public class ChangeSort {       public S ...

  7. 《面向对象程序设计》第三次作业 Calculator

    c++第三次作业 Calculator git上的作业展示点这里. ps:有一点不是很明确,作业要求:将数字和符号提取出来,得到一组string,然后才将这些string存入队列中.按我的理解是需要将 ...

  8. “数学口袋精灵”第二个Sprint计划(第九天)

    第九天进度 任务分配: 冯美欣:欢迎界面背景音乐发现bug(一开始进入游戏可以播放音乐,进入游戏界面,再返回欢迎界面时,音乐播放不出来),仍在解决中: 吴舒婷:改进ui与音效 1.进度条.金黄色: 2 ...

  9. “数学口袋精灵”第二个Sprint计划(第六~八天)

    “数学口袋精灵”第二个Sprint计划----第六天~第八天进度 任务分配: 冯美欣:欢迎界面的背景音乐完善 吴舒婷:游戏界面的动作条,选择答案后的音效 林欢雯:代码算法设计 第六天: 进度: 冯美欣 ...

  10. 推广App篇

    推广App篇 团队github地址:https://github.com/ouqifeng/EasyGoOperation.git 在完成该项目工程后,我们开始寻找合适的方法推广我们的软件. 经过一番 ...