加密签名

web应用安全的黄金法则是,永远不要相信来自不可信来源的数据。有时通过不可信的媒介来传递数据会非常方便。密码签名后的值可以通过不受信任的途径传递,这样是安全的,因为任何篡改都会检测的到。

Django提供了用于签名的底层API,以及用于设置和读取被签名cookie的上层API,它们是web应用中最常使用的签名工具之一。

你可能会发现,签名对于以下事情非常有用:

  • 生成用于“重置我的账户”的URL,并发送给丢失密码的用户。

  • 确保储存在隐藏表单字段的数据不被篡改,

  • 生成一次性的秘密URL,用于暂时性允许访问受保护的资源,例如用户付费的下载文件。

保护 SECRET_KEY

当你使用 startproject创建新的Django项目时,自动生成的 settings.py文件会得到一个随机的SECRET_KEY值。这个值是保护签名数据的密钥 -- 它至关重要,你必须妥善保管,否则攻击者会使用它来生成自己的签名值。

使用底层 API

Django的签名方法存放于django.core.signing模块。首先创建一个 Signer 的实例来对一个值签名:

>>> from django.core.signing import Signer
>>> signer = Signer()
>>> value = signer.sign('My string')
>>> value
'My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w'

这个签名会附加到字符串末尾,跟在冒号后面。你可以使用unsign方法来获取原始的值:

>>> original = signer.unsign(value)
>>> original
'My string'

如果签名或者值以任何方式改变,会抛出django.core.signing.BadSignature 异常:

>>> from django.core import signing
>>> value += 'm'
>>> try:
...    original = signer.unsign(value)
... except signing.BadSignature:
...    print("Tampering detected!")

通常,Signer类使用SECRET_KEY设置来生成签名。你可以通过向Signer构造器传递一个不同的密钥来使用它:

>>> signer = Signer('my-other-secret')
>>> value = signer.sign('My string')
>>> value
'My string:EkfQJafvGyiofrdGnuthdxImIJw'

class Signer(key=None, sep=':', salt=None)[source]

返回一个signer,它使用key 来生成签名,并且使用sep来分割值。sep 不能是 [URL安全的base64字母表(http://tools.ietf.org/html/rfc4648#section-5)]中的字符。字母表含有数字、字母、连字符和下划线。

使用salt参数

如果你不希望对每个特定的字符串都生成一个相同的签名哈希值,你可以在Signer类中使用可选的salt 参数。使用salt参数会同时用它和SECRET_KEY初始化签名哈希函数:

>>> signer = Signer()
>>> signer.sign('My string')
'My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w'
>>> signer = Signer(salt='extra')
>>> signer.sign('My string')
'My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw'
>>> signer.unsign('My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw')
'My string'

以这种方法使用salt会把不同的签名放在不同的命名空间中。来自于单一命名空间(一个特定的salt值)的签名不能用于在不同的命名空间中验证相同的纯文本字符串。不同的命名空间使用不同的salt设置。这是为了防止攻击者使用在一个地方的代码中生成的签名后的字符串,作为使用不同salt来生成(和验证)签名的另一处代码的输入。

不像你的SECRET_KEY,你的salt参数可以不用保密。

验证带有时间戳的值

TimestampSignerSigner的子类,它向值附加一个签名后的时间戳。这可以让你确认一个签名后的值是否在特定时间段之内被创建:

>>> from datetime import timedelta
>>> from django.core.signing import TimestampSigner
>>> signer = TimestampSigner()
>>> value = signer.sign('hello')
>>> value
'hello:1NMg5H:oPVuCqlJWmChm1rA2lyTUtelC-c'
>>> signer.unsign(value)
'hello'
>>> signer.unsign(value, max_age=10)
...
SignatureExpired: Signature age 15.5289158821 > 10 seconds
>>> signer.unsign(value, max_age=20)
'hello'
>>> signer.unsign(value, max_age=timedelta(seconds=20))
'hello'

class TimestampSigner(key=None, sep=':', salt=None)[source]

sign(value)[source]

签名value,并且附加当前的时间戳。

unsign(value, max_age=None)[source]

检查value是否在少于max_age 秒之前被签名,如果不是则抛出SignatureExpired异常。max_age 参数接受一个整数或者datetime.timedelta对象。

Changed in Django 1.8:在此之前, max_age参数只接受整数。

保护复杂的数据结构

如果你希望保护一个列表、元组或字典,你可以使用签名模块的dumpsloads 函数来实现。它们模仿了Python的pickle模块,但是在背后使用了JSON序列化。JSON可以确保即使你的SECRET_KEY被盗取,攻击者并不能利用pickle的格式来执行任意的命令:

>>> from django.core import signing
>>> value = signing.dumps({"foo": "bar"})
>>> value
'eyJmb28iOiJiYXIifQ:1NMg1b:zGcDE4-TCkaeGzLeW9UQwZesciI'
>>> signing.loads(value)
{'foo': 'bar'}

由于JSON的本质(列表和元组之间没有原生的区别),如果你传进来一个元组,你会从signing.loads(object)得到一个列表:

>>> from django.core import signing
>>> value = signing.dumps(('a','b','c'))
>>> signing.loads(value)
['a', 'b', 'c']

dumps(obj, key=None, salt='django.core.signing', compress=False)[source]

返回URL安全,sha1签名的base64压缩的JSON字符串。序列化的对象使用TimestampSigner来签名。

loads(string, key=None, salt='django.core.signing', max_age=None)[source]

dumps()的反转,如果签名失败则抛出BadSignature异常。如果提供了max_age则会检查它(以秒为单位)。

译者:Django 文档协作翻译小组,原文:Cryptographic signing。

本文以 CC BY-NC-SA 3.0 协议发布,转载请保留作者署名和文章出处。

Django 文档协作翻译小组人手紧缺,有兴趣的朋友可以加入我们,完全公益性质。交流群:467338606。

django 1.8 官方文档翻译:8-5 加密签名相关推荐

  1. django 1.8 官方文档翻译: 2-5-7 自定义查找

    自定义查找 New in Django 1.7. Django为过滤提供了大量的内建的查找(例如,exact和icontains).这篇文档阐述了如何编写自定义查找,以及如何修改现存查找的功能.关于查 ...

  2. django 1.8 官方文档翻译: 13-9-1 如何使用会话

    如何使用会话 Django 提供对匿名会话的完全支持.其会话框架让你根据各个站点的访问者存储和访问任意数据.它在服务器端存储数据并抽象Cookie 的发送和接收.Cookie 包含会话的ID -- 不 ...

  3. django 1.8 官方文档翻译: 2-5-6 多数据库

    多数据库 这篇主题描述Django 对多个数据库的支持.大部分Django 文档假设你只和一个数据库打交道.如果你想与多个数据库打交道,你将需要一些额外的步骤. 定义你的数据库 在Django中使用多 ...

  4. django 1.8 官方文档翻译: 1-1-2 快速安装指南

    快速安装指南 在你开始使用 Django 之前,你需要先安装它.我们有一个 完整安装指南 它涵盖了所有的安装步骤和可能遇到的问题:本指南将会给你一个最简单.简洁的安装指引. 安装 Python 作为一 ...

  5. django 1.8 官方文档翻译: 3-4-2 基于类的内建通用视图

    基于类的内建通用视图 编写Web应用可能是单调的,因为你需要不断的重复某一种模式. Django尝试从model和 template层移除一些单调的情况,但是Web开发者依然会在view(视图)层经历 ...

  6. django 1.8 官方文档翻译:2-5-9 条件表达式

    条件表达式 New in Django 1.8. 条件表达式允许你在过滤器.注解.聚合和更新操作中使用 if ... elif ... else的逻辑.条件表达式为表中的每一行计算一系列的条件,并且返 ...

  7. django 1.8 官方文档翻译: 3-4-2 内建显示视图

    Django 文档协作翻译小组人手紧缺,有兴趣的朋友可以加入我们,完全公益性质. 交流群:467338606 网站:http://python.usyiyi.cn/django/index.html ...

  8. django 1.8 官方文档翻译:2-1-1 模型语法

    模型 模型是你的数据的唯一的.权威的信息源.它包含你所储存数据的必要字段和行为.通常,每个模型对应数据库中唯一的一张表. 基础: 每个模型都是django.db.models.Model 的一个Pyt ...

  9. django 1.8 官方文档翻译:6-3 Django异常

    Django异常 DJango会抛出一些它自己的异常,以及Python的标准异常. Django核心异常 Django核心异常类定义在django.core.exceptions中. ObjectDo ...

最新文章

  1. INTERSECT/EXCEPT VS. IN/NOT IN
  2. K-近邻算法之案例2:预测facebook签到位置
  3. 如何防止按钮提交表单
  4. uni-app——map组件路线[polyline]功能示例
  5. 关于迭代測试的一些思考
  6. jpa 测试_使用外星人进行测试:如何使用Arquillian测试JPA类型转换器
  7. 线条边框简笔画图片大全_儿童简笔画画大全人物
  8. 重建道路(洛谷-P1272)
  9. 从零基础入门Tensorflow2.0 ----八、39.3. gpu3
  10. 计算机组成原理(白中英) 第四章 课后题答案
  11. 【读书笔记】《王道论坛计算机考研机试指南》第二章
  12. 计算平均指令时间_欧姆龙PLC指令应用案例(问答解析)
  13. tkmybatis 权威指南 官方文档
  14. 常用windows系统的100个dos命令
  15. 穷查理宝典_《穷查理宝典》(珍藏版)
  16. 在Adobe Premiere Pro for Mac上使用合并剪辑同步音频和视频
  17. Straight lines have to be straight
  18. PHP中explode()和implode()函数讲解和实战用法
  19. 网络安全笔记-26-Linux-基础
  20. 基于人脸识别的课堂考勤系统 tkinter+openpyxl+face_recognition

热门文章

  1. 常用数据结构及复杂度
  2. Java集合—PriorityQueue底层原理
  3. mysql索引实现原理
  4. Android魔法(第三弹)—— 一步步实现对折页面
  5. SDNU 1029.巧分整数(斯特林数(改)dp)
  6. 操作系统页面置换算法
  7. day 96 关于分页的使用
  8. 第八章 springboot + mybatis + 多数据源
  9. Atitit.mybatis的测试  以及spring与mybatis在本项目中的集成配置说明
  10. Barracuda VS antelope