名前衝突の可能性のない数千のファイルについて、8文字の短い一意のランダムなファイル名を計算しようとしています。この方法は十分に安全ですか?
base64.urlsafe_b64encode(hashlib.md5(os.urandom(128)).digest())[:8]
明確にするために、ストレージにアップロードされるファイル名の最も単純な難読化を達成しようとしています。
十分にランダムな8文字の文字列は、正しく実装されていれば、衝突の可能性なしに何万ものファイルを保存する非常に効率的で簡単な方法であることがわかりました。一意性を保証する必要はなく、名前の衝突の可能性が十分に高いだけです(数千の名前についてのみ話しています)。
ファイルはコンカレント環境に保存されているため、共有カウンターを増やすことは可能ですが、複雑です。データベースにカウンターを保存するのは非効率です。
また、状況によってはrandom()がsamedifferentプロセスの擬似ランダムシーケンスを返すという事実に直面しています。
tempfile
を使用して名前を生成できない理由はありますか?
mkstemp
やNamedTemporaryFile
などの関数は、一意の名前を与えることが絶対に保証されています。ランダムバイトに基づくものは何もあなたにそれを与えるつもりはありません。
何らかの理由で実際にファイルを作成したくない場合(たとえば、リモートサーバーなどで使用するファイル名を生成している場合)、完全に安全ではありませんが、mktemp
はまだですランダムな名前よりも安全です。
または、単に「グローバルに十分な」場所に48ビットカウンタを保存しておくと、衝突の前に名前の完全なサイクルを通過することを保証し、衝突がいつ発生するかを確実に知ることができます。
これらはすべてurandom
を読んで_md5
_を実行するよりも安全でシンプルで、はるかに効率的です。
本当にランダムな名前を生成したい場合は、''.join(random.choice(my_charset) for _ in range(8))
もあなたがやっていることよりも簡単で、より効率的になります。 urlsafe_b64encode(os.urandom(6))
でさえ、MD5ハッシュと同じくらいランダムで、よりシンプルで効率的です。
暗号のランダム性および/または暗号ハッシュ関数の唯一の利点は、予測可能性を回避することです。それがあなたにとって問題でない場合、なぜそれを支払うのですか?また、予測可能性を回避する必要がある場合、ほぼ確実に人種やその他のはるかに単純な攻撃を回避する必要があるため、mkstemp
またはNamedTemporaryFile
を回避することは非常に悪い考えです。
言うまでもなく、Rootがコメントで指摘しているように、セキュリティが必要な場合、MD5は実際にセキュリティを提供しません。
現在のメソッドは十分に安全であるはずですが、 uuid
モジュールを調べることもできます。例えば.
import uuid
print str(uuid.uuid4())[:8]
出力:
ef21b9ad
shortuuid ライブラリを試すことができます。
でインストール:pip install shortuuid
それは次のように簡単です:
> import shortuuid
> shortuuid.uuid()
'vytxeTZskVKR7C7WgdSP3d'
random.choice()
は少し高速で、約3桁あります衝突が少ないですが、わずかにIMOです読みにくい。
import string
import uuid
import random
def random_choice():
alphabet = string.ascii_lowercase + string.digits
return ''.join(random.choices(alphabet, k=8))
def truncated_uuid4():
return str(uuid.uuid4())[:8]
def test_collisions(fun):
out = set()
count = 0
for _ in range(1000000):
new = fun()
if new in out:
count += 1
else:
out.add(new)
print(count)
test_collisions(random_choice)
test_collisions(truncated_uuid4)
セットからの8文字のUUIDの1,000万回の描画による単一実行の結果abcdefghijklmnopqrstuvwxyz0123456789
。ランダム選択と切り捨てられたuuid4:
これを試すことができます
import random
uid_chars = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
'v', 'w', 'x', 'y', 'z','1','2','3','4','5','6','7','8','9','0')
uid_length=8
def short_uid():
count=len(uid_chars)-1
c=''
for i in range(0,uid_length):
c+=uid_chars[random.randint(0,count)]
return c
例えば:
print short_uid()
nogbomcv
hashids を使用して、タイムスタンプを一意のIDに変換しています。 (必要に応じて、タイムスタンプに戻すこともできます)。
これの欠点は、IDの作成が速すぎると重複することです。しかし、それらを中間の時間で生成する場合、これはオプションです。
以下に例を示します。
from hashids import Hashids
from datetime import datetime
hashids = Hashids(salt = "lorem ipsum dolor sit amet", alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
print(hashids.encode(int(datetime.today().timestamp()))) #'QJW60PJ1' when I ran it