django1.8官方文件翻譯:8-5加密簽名

apachecn_飛龍發表於2015-09-16

加密簽名

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。


相關文章