Достаточно безопасная 8-символьная короткая уникальная случайная строка
Я пытаюсь вычислить 8-символьные короткие уникальные случайные имена файлов, скажем, тысячи файлов без вероятного столкновения имен. Является ли этот метод достаточно безопасным?
base64.urlsafe_b64encode(hashlib.md5(os.urandom(128)).digest())[:8]
Изменить
Чтобы быть яснее, я пытаюсь добиться простейшей возможной обфускации имен файлов, загружаемых в хранилище.
Я понял, что 8-символьная строка, достаточно случайная, будет очень эффективным и простым способом хранения десятков тысяч файлов без вероятного столкновения при правильной реализации. Мне не нужна гарантированная уникальность, только достаточно высокая невероятность столкновения имен (речь идет только о тысячах имен).
Файлы хранятся в параллельной среде, поэтому увеличение общего счетчика является достижимым, но сложным. Хранение счетчика в базе данных будет неэффективным.
Я также сталкиваюсь с тем фактом, что random() при некоторых обстоятельствах возвращает одинаковые псевдослучайные последовательности в разных процессах.
Ответы
Ответ 1
Есть ли причина, по которой вы не можете использовать 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 на самом деле не предоставляет его.
Ответ 2
Ваш текущий метод должен быть достаточно безопасным, но вы также можете заглянуть в модуль uuid
. например.
import uuid
print str(uuid.uuid4())[:8]
Вывод:
ef21b9ad
Ответ 3
Вы можете попробовать это
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
Ответ 4
как насчет случайного 8-значного числа? random.randrange(10**8)
import random
print random.randrange(10**8)
print '----------------------'
for x in xrange(10):
print '{:08}'.format(random.randrange(10**8))
выход:
$ python foo.py
36714482
----------------------
09000782
82536385
29075031
43364370
81089457
53010521
12030602
69531566
07898400
38782440
Ответ 5
Я использую хеш-коды для преобразования временной метки в уникальный идентификатор. (Вы можете даже преобразовать его обратно в метку времени, если хотите).
Недостатком этого является то, что если вы создаете слишком быстро идентификаторы, вы получите дубликат. Но, если вы генерируете их со временем, то это вариант.
Вот пример:
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
Ответ 6
Вы можете попробовать библиотеку shortuuid.
Установить с помощью: pip install shortuuid
Тогда это так просто, как:
> import shortuuid
> shortuuid.uuid()
'vytxeTZskVKR7C7WgdSP3d'