revision-up-to: | 17812 (1.4) |
---|
リリースノートを参照してください
Web アプリケーションセキュリティの黄金律は、信頼できないソースからのデータを決 して信頼しないということです。しかし時には信頼できない媒体にデータを通すことが 便利かもしれません。暗号により署名された値を使えば、どんな改ざんも検出されると いう知識のもとで、信頼できない経路を安全に通過できます。
Django は値を署名するための低レベル API と、署名つきクッキーを設定したり読み込 むための高レベル API を提供しています。署名つきクッキーは Web アプリケーション で最もよく使われる署名の一つです。
また、次のような場合に署名が使えることにお気づきでしょうか:
startproject
を使って新しく Django プロジェクトを作成すると、
settings.py
ファイルが自動的に生成され SECRET_KEY
にはランダム
値がセットされます。この値はデータを安全に署名するためのキーなので、このキーを
秘密に保つことが不可欠です。そうしなければ攻撃者がキーを使って自分の署名された
値を生成できてしまうでしょう。
Signer
¶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
u'My string'
署名または値が何らかの方法で変更されると、 django.core.signing.BadSignature
例外が送出されます:
>>> 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'
同じ文字列に対して毎回同じ署名ハッシュを取得したくないなら、オプションの
salt
引数を Signer
クラスに使うことができます。ソルトを使うと 署名ハッ
シュ関数はソルトと 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')
u'My string'
このようにソルトを使うと、署名が別々の名前空間に置かれます。同じプレーンテキス トの検証でも、特定のソルト値を使ったある名前空間から得られた署名を、別のソルト を設定した名前空間で使うことはできません。この結果により、コードのある場所で生 成された署名つき文字列を、違うソルトを使って生成 (検証) している別の場所への入 力として攻撃者が使うことを防げます。
SECRET_KEY
と違って、ソルト引数は秘密にする必要がありません。
TimestampSigner
¶TimestampSigner
は Signer
のサブクラスで、署名つきタイムスタンプ
を値に付け加えます。これによって署名された値が特定の期間に作られたことを確認で
きます:
>>> from django.core.signing import TimestampSigner
>>> signer = TimestampSigner()
>>> value = signer.sign('hello')
>>> value
'hello:1NMg5H:oPVuCqlJWmChm1rA2lyTUtelC-c'
>>> signer.unsign(value)
u'hello'
>>> signer.unsign(value, max_age=10)
...
SignatureExpired: Signature age 15.5289158821 > 10 seconds
>>> signer.unsign(value, max_age=20)
u'hello'
リストやタプルや辞書を保護したいのであれば、 signing モジュールの dumps
と
loads
関数を使ってください。これらの関数は 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'}
dumps
(obj, key=None, salt='django.core.signing', compress=False)¶sha1 で署名され base64 で圧縮された URL を安全に使える JSON 文字列を返しま す。
loads
(string, key=None, salt='django.core.signing', max_age=None)¶dumps() の逆です。署名が間違っていると BadSignature
を送出します。
Oct 26, 2017