足够安全的8个字符的短唯一的随机字符串(safe enough 8-character short

2019-08-03 00:32发布

我试图计算为8个字符的短唯一的随机文件名,比方说,成千上万的文件,而不可能名称冲突。 这是方法足够安全?

base64.urlsafe_b64encode(hashlib.md5(os.urandom(128)).digest())[:8]

编辑

为了更清楚,我想实现简单的文件名可能被混淆上传到存储。

我想通了,8个字符的字符串,足够的随机,将文件数万存储无疑似碰撞,实施正确的时候非常有效和简单的方式。 我并不需要保证唯一性,名称冲突(谈论仅几千名的)的只有足够高的不可能性。

文件被存储在并发环境中,因此增加共用的反是可以实现的,但复杂。 在数据库中存储计数器将是低效的。

我也面临着随机的()在某些情况下返回不同的工艺相同的伪随机序列的事实。

Answer 1:

有没有什么不能使用的原因tempfile生成的名字呢?

像函数mkstempNamedTemporaryFile绝对保证给你独一无二的名称; 基于随机字节没有什么能比给你的。

如果由于某种原因,你其实不愿意尚未创建文件(例如,您正在生成被一些远程服务器或东西上使用的文件名),你不能是完全安全的,但mktemp仍比随机名称更安全。

或者只是保持存储在一些“全球性不够”位置的48位计数器,所以你保证碰撞之前通过名称的完整循环下去,你也保证在发生碰撞时会发生什么了解。

他们都是比阅读更安全,更简单,而且更有效urandom和做的md5

如果你确实想要生成随机的名字, ''.join(random.choice(my_charset) for _ in range(8))也将是比你在做什么更简单,更高效。 即使urlsafe_b64encode(os.urandom(6))只是随机的MD5哈希值,以及更简单,更高效。

加密随机性和/或密码散列函数的唯一的好处是避免可预测性。 如果这不是你的问题,为什么支付? 如果你确实需要避免可预测性,你几乎肯定需要避免种族和其他更简单的攻击,所以避免mkstempNamedTemporaryFile是一个非常糟糕的主意。

更何况,作为根在评论中指出,如果你需要的安全,MD5实际上并没有提供它。



Answer 2:

您当前的方法应该是足够安全的,但你也可以看看到uuid模块。 例如

import uuid

print str(uuid.uuid4())[:8]

输出:

ef21b9ad


Answer 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


Answer 4:

你可以尝试shortuuid库。

与安装: pip install shortuuid

然后,它是非常简单:

> import shortuuid
> shortuuid.uuid()
'vytxeTZskVKR7C7WgdSP3d'


Answer 5:

哪种方法具有较少的碰撞,更快,更容易阅读?

TLDR

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)

样品试运行

在1000万单次运行结果得出的8字符的UUID从集合abcdefghijklmnopqrstuvwxyz0123456789 。 随机选择VS截断uuid4:

  • 碰撞:17 - 11632
  • 时间(秒):37 - 63


Answer 6:

我使用hashids的时间戳转换成一个唯一的ID。 (你甚至可以将其转换回时间戳如果你想)。

这样做的缺点是,如果你创建IDS太快,你会得到一个副本。 但是,如果你用的时间产生在他们之间,那么这是一个选项。

下面是一个例子:

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


文章来源: safe enough 8-character short unique random string