一般的な概念—その危険なドキュメント
一般的な概念
シリアライザーと署名者
itsDangerousは、2つのレベルのデータ処理を提供します。 署名インターフェースは、指定された署名パラメーターに基づいて、指定されたbytes
値に署名する基本システムです。 Serialization Interface は署名者をラップして、bytes
以外の他のデータのシリアル化と署名を可能にします。
通常、署名者ではなくシリアライザーを使用することをお勧めします。 シリアライザーを介して署名パラメーターを構成でき、フォールバック署名者を提供して古いトークンを新しいパラメーターにアップグレードすることもできます。
秘密の鍵
署名はsecret_key
によって保護されています。 通常、1つの秘密鍵がすべての署名者で使用され、ソルトはさまざまなコンテキストを区別するために使用されます。 秘密鍵を変更すると、既存のトークンが無効になります。
ランダムな長いバイト文字列である必要があります。 この値は秘密にしておく必要があり、ソースコードに保存したり、バージョン管理にコミットしたりしないでください。 攻撃者が秘密鍵を知った場合、データを変更して辞任し、有効に見えるようにすることができます。 これが発生したと思われる場合は、秘密鍵を変更して既存のトークンを無効にします。
秘密鍵を分離しておく1つの方法は、環境変数から秘密鍵を読み取ることです。 初めてデプロイするときは、キーを生成し、アプリケーションの実行時に環境変数を設定します。 すべてのプロセスマネージャー(systemdなど)とホスティングサービスには、環境変数を指定する方法があります。
import os
from itsdangerous.serializer import Serializer
SECRET_KEY = os.environ.get("SECRET_KEY")
s = Serializer(SECRET_KEY)
$ export SECRET_KEY="base64 encoded random bytes"
$ python application.py
キーを生成する1つの方法は、os.urandom()
を使用することです。
$ python3 -c 'import os; print(os.urandom(16).hex())'
塩
ソルトは秘密鍵と組み合わされて、さまざまなコンテキストを区別するための一意の鍵を導き出します。 秘密鍵とは異なり、ソルトはランダムである必要はなく、コードに保存できます。 プライベートではなく、コンテキスト間で一意である必要があります。
たとえば、アクティベーションリンクを電子メールで送信してユーザーアカウントをアクティベートし、リンクをアップグレードしてユーザーを有料アカウントにアップグレードするとします。 署名するのがユーザーIDだけで、別のソルトを使用しない場合、ユーザーはアクティベーションリンクのトークンを再利用してアカウントをアップグレードできます。 異なるソルトを使用すると、署名が異なり、他のコンテキストでは無効になります。
from itsdangerous.url_safe import URLSafeSerializer
s1 = URLSafeSerializer("secret-key", salt="activate")
s1.dumps(42)
'NDI.MHQqszw6Wc81wOBQszCrEE_RlzY'
s2 = URLSafeSerializer("secret-key", salt="upgrade")
s2.dumps(42)
'NDI.c0MpsD6gzpilOAeUPra3NShPXsE'
2番目のシリアライザーは、ソルトが異なるため、最初のシリアライザーでダンプされたデータをロードできません。
s2.loads(s1.dumps(42))
Traceback (most recent call last):
...
BadSignature: Signature does not match
同じソルトのシリアライザーのみがデータをロードできます。
s2.loads(s2.dumps(42))
42
キーローテーション
キーローテーションは、攻撃者が秘密キーを発見することに対する追加の緩和層を提供できます。 ローテーションシステムは、有効なキーのリストを保持し、新しいキーを生成し、最も古いキーを定期的に削除します。 攻撃者がキーを解読するのに4週間かかるが、3週間後にキーがローテーションされた場合、攻撃者は解読したキーを使用できなくなります。 ただし、ユーザーが3週間以内にトークンを更新しないと、トークンも無効になります。
このリストを生成および維持するシステムはItsDangerousの範囲外ですが、ItsDangerousはキーのリストに対する検証をサポートしています。
単一のキーを渡す代わりに、古いものから新しいものへとキーのリストを渡すことができます。 署名するときは最後の(最新の)キーが使用され、検証するときは検証エラーが発生する前に各キーが新しいものから古いものへと試行されます。
SECRET_KEYS = ["2b9cd98e", "169d7886", "b6af09f5"]
# sign some data with the latest key
s = Serializer(SECRET_KEYS)
t = s.dumps({"id": 42})
# rotate a new key in and the oldest key out
SECRET_KEYS.append("cf9b3588")
del SECRET_KEYS[0]
s = Serializer(SECRET_KEYS)
s.loads(t) # valid even though it was signed with a previous key
ダイジェストメソッドのセキュリティ
署名者は、digest_method
で構成されます。これは、HMAC署名を生成する際の中間ステップとして使用されるハッシュ関数です。 デフォルトの方法はhashlib.sha1()
です。 時折、SHA-1とのハッシュ衝突について聞いたことがあるため、ユーザーはこのデフォルトについて心配することがあります。
HMACで中間の反復ステップとして使用される場合、SHA-1は安全ではありません。 実際、MD5でさえHMACではまだ安全です。 HMACで使用する場合、ハッシュのみのセキュリティは適用されません。
プロジェクトがSHA-1をリスクと見なす場合は、hashlib.sha512()
などの別のダイジェスト方法で署名者を構成できます。 SHA-1のフォールバック署名者は、古いトークンがアップグレードされるように構成できます。 SHA-512はより長いハッシュを生成するため、トークンはより多くのスペースを占有します。これはCookieとURLに関連しています。