有効期間が約「2 日」の内部セッションを表すために、最大 21 文字の名前を持つ API を使用しています。ある種のハッシュを使用して名前を意味のあるものにしないでください。md5 は 40 文字を生成します。他に使用できるものはありますか?
今のところ、「userid[:10]」 + 作成時間: ddhhmmss + ランダムな 3 文字を使用します。
ありがとう、
有効期間が約「2 日」の内部セッションを表すために、最大 21 文字の名前を持つ API を使用しています。ある種のハッシュを使用して名前を意味のあるものにしないでください。md5 は 40 文字を生成します。他に使用できるものはありますか?
今のところ、「userid[:10]」 + 作成時間: ddhhmmss + ランダムな 3 文字を使用します。
ありがとう、
あなたの質問を正しく読んだ場合、最大 21 文字の任意の識別子トークンを生成する必要があります。推測に対して非常に耐性がある必要がありますか? あなたが示した例は、可能なキースペース全体の1/2未満を十分に検索することで推測できるという点で、「暗号的に強力」ではありません。
文字がすべて 256 の ASCII 文字にできるかどうか、または印刷可能な ASCII (33-127 を含む)、またはより小さな範囲に制限する必要があるかどうかはわかりません。
UUID (Universals Unique IDentifiers)用に設計された Python モジュールがあります。ランダムな UUID を生成し、利用可能な場合は OS サポートを使用する uuid4 が必要になる可能性があります (Linux、Mac、FreeBSD など)。
>>> import uuid
>>> u = uuid.uuid4()
>>> u
UUID('d94303e7-1be4-49ef-92f2-472bc4b4286d')
>>> u.bytes
'\xd9C\x03\xe7\x1b\xe4I\xef\x92\xf2G+\xc4\xb4(m'
>>> len(u.bytes)
16
>>>
16 のランダム バイトは非常に推測しにくく、推測できない不透明な識別子が必要な場合は、API で許可されている 21 バイトをすべて使用する必要はありません。
そのような生のバイトを使用できない場合は、ログやその他のデバッグ メッセージで使用するのが難しく、目で比較するのが難しいため、おそらく悪い考えです。base- を使用するなど、バイトをもう少し読みやすいものに変換します64 エンコーディング、結果は 21 (またはその他) バイトに切り詰められます。
>>> u.bytes.encode("base64")
'2UMD5xvkSe+S8kcrxLQobQ==\n'
>>> len(u.bytes.encode("base64"))
25
>>> u.bytes.encode("base64")[:21]
'2UMD5xvkSe+S8kcrxLQob'
>>>
これにより、長さ 21 の非常に高品質なランダム文字列が得られます。
適切なエスケープがないと URL に干渉する可能性があるため、base-64 文字列に含まれる「+」または「/」が気に入らない場合があります。「ランダムな3文字」を使用することをすでに考えているので、これはあなたの心配ではないと思います. そうである場合は、それらの文字を別のものに置き換えるか ('-' と '.' が機能する可能性があります)、存在する場合は削除することができます。
他の人が指摘したように、.encode("hex") を使用して同等の 16 進数を取得できますが、それは 4 ビットのランダム性/文字です * 最大 21 文字で、2 倍ではなく 84 ビットのランダム性が得られます。すべてのビットでキースペースが 2 倍になり、理論上の検索スペースがはるかに小さくなります。2E24 より小さい。
あなたのキースペースは、16進エンコーディングを使用してもサイズが2E24のままであるため、理論的な問題だと思います。あなたのシステムに対してブルート フォース攻撃を行う人を心配する必要はありません。
編集:
PS: uuid.uuid4 関数は、可能であれば libuuid を使用します。これは、os.urandom (利用可能な場合) からエントロピーを取得します。それ以外の場合は、現在の時刻とローカル イーサネット MAC アドレスから取得します。libuuid が利用できない場合、uuid.uuid4 関数は (利用可能な場合) os.urandom から直接バイトを取得します。それ以外の場合は、random モジュールを使用します。random モジュールは、os.urandom (利用可能な場合) に基づくデフォルトのシードを使用します。それ以外の場合は、現在の時刻に基づく値です。プロービングはすべての関数呼び出しに対して行われるため、os.urandom がない場合、オーバーヘッドは予想よりも少し大きくなります。
メッセージをお持ち帰り?os.urandom があることがわかっている場合は、実行できます
os.urandom(16).encode("base64")[:21]
しかし、その可用性について心配したくない場合は、uuid モジュールを使用してください。
MD5 の 16 進表現のランダム性は非常に低く、1 文字あたり 4 ビットのエントロピーしか得られません。
次のようなランダムな文字を使用します。
import random
import string
"".join([random.choice(string.ascii_letters + string.digits + ".-")
for i in xrange(21)])
選択肢には、受け入れ可能なすべての文字を入れてください。
SHA1 などの実際のハッシュ関数を使用しても、正しく使用すれば優れた結果が得られますが、複雑さが増し、CPU 消費量が増えるため、ニーズに合わないようです。ランダムな文字列のみが必要です。
base64 モジュールは、URL セーフ エンコーディングを実行できます。したがって、必要に応じて、代わりに
u.bytes.encode("base64")
あなたができる
import base64
token = base64.urlsafe_b64encode(u.bytes)
そして、便利なことに、元に戻す
u = uuid.UUID(bytes=base64.urlsafe_b64decode(token))
md5 または SHA1 ハッシュから最初の 21 文字を取得しないのはなぜですか?
文字ですか、それともバイトですか?任意の文字列を使用する場合は、バイトを使用するだけで、読み取り可能な文字に拡張することを心配する必要はありません (とにかく、16 進数よりも base64 の方が優れています)。
16 進展開を使用しない場合、MD5 は 16 文字を生成します。SHA1 は同じ条件で 20 を生成します。
>>> import hashlib
>>> len(hashlib.md5('foobar').digest())
16
>>> len(hashlib.sha1('foobar').digest())
20
その後、いくつかの余分なバイトが必要です。