Pergunta

Eu estou usando uma API que leva um nome de 21 max char para representar uma sessão interna, que tem uma vida útil de cerca de "dois dias". Eu gostaria que o nome não ser meaningfull usando algum tipo de hasing? md5 gera 40 caracteres, há algo mais que eu poderia usar?

Para uso agora eu 'id do usuário [: 10]' + tempo de criação:. Ddhhmmss + aleatórios 3 caracteres

Obrigado,

Foi útil?

Solução

Se eu ler a sua pergunta corretamente, você quer gerar algum arbitrária token identificador que deve ter 21 caracteres no máximo. Será que ela precisa para ser altamente resistente a adivinhar? O exemplo que você deu não é "crytographically forte" na medida em que pode ser adivinhada por pesquisar bem menos de 1/2 de toda a keyspace possível.

Você não diz se os personagens podem ser todos os 256 caracteres ASCII, ou se ele precisa ser limitado a, digamos, em ASCII (33-127, inclusive), ou algum intervalo menor.

Existe um módulo Python projetada para UUID s (Universals identificadores exclusivos). Você provavelmente quer uuid4 que gera um UUID aleatório, e usa o suporte OS se disponível (em Linux, Mac, FreeBSD, e provavelmente outros).

>>> 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 bytes aleatórios é muito unguessable, e não há necessidade de usar o completo 21 bytes sua API permite que, se tudo que você quer é ter um identificador opaco unguessable.

Se você não pode usar bytes matérias como essa, que é provavelmente uma má idéia, porque é mais difícil de usar em toras e outras mensagens de depuração e mais difícil de comparar por olho, em seguida, converter os bytes em algo um pouco mais legível, como utilizando uma base-64 que codifica, com o resultado triturada até 21 (ou qualquer outro) bytes:

>>> u.bytes.encode("base64")
'2UMD5xvkSe+S8kcrxLQobQ==\n'
>>> len(u.bytes.encode("base64")) 
25
>>> u.bytes.encode("base64")[:21]
'2UMD5xvkSe+S8kcrxLQob'
>>> 

Isto dá-lhe uma cadeia de extrema qualidade aleatório de comprimento 21.

Você pode não gostar do '+' ou '/', que pode estar em uma string base-64, uma vez que sem a devida escapar que possa interferir com URLs. Desde que você já pensou em usar "aleatórios de 3 caracteres", eu não acho que isso é uma preocupação de vocês. Se for, você poderia substituir os caracteres com outra coisa ( '-' '' eo trabalho poder)., Ou removê-los se estiverem presentes

Como outros apontaram, você poderia usar .encode ( "hex") e obter o equivalente hexadecimal, mas isso é apenas 4 bits de aleatoriedade / personagem * 21 caracteres no máximo lhe dá 84 bits de aleatoriedade em vez de duas vezes isso. Cada bit duplica o seu keyspace, tornando o espaço de pesquisa teórica muito, muito menor. Por um fator de 2E24 menor.

Seu keyspace ainda é 2E24 em tamanho, mesmo com a codificação hexadecimal, então eu acho que é mais uma preocupação teórica. Eu não me preocuparia com pessoas fazendo ataques de força bruta contra seu sistema.

Editar :

P.S .: Os usos função uuid.uuid4 libuuid se disponível. Que obtém sua entropia de os.urandom (se disponível), caso contrário a partir do momento atual e o endereço Ethernet MAC local. Se libuuid não está disponível, em seguida, a função uuid.uuid4 recebe os bytes diretamente do os.urandom (se disponível), caso contrário ele usa o módulo aleatório. O módulo aleatório utiliza uma semente padrão baseado em os.urandom (se disponível), caso contrário um valor baseado no tempo atual. Sondagem ocorre para cada chamada de função, por isso, se você não tem os.urandom seguida, a sobrecarga é um pouco maior do que você poderia esperar.

mensagem para levar para casa? Se você sabe que tem os.urandom então você poderia fazer

os.urandom(16).encode("base64")[:21]

mas se você não quer se preocupar com a sua disponibilidade, em seguida, usar o módulo uuid.

Outras dicas

A representação hexadecimal de MD5 tem muito pobre aleatoriedade:. Você só tem 4 bits de entropia por personagem

Use caracteres aleatórios, algo como:

import random
import string
"".join([random.choice(string.ascii_letters + string.digits + ".-")
        for i in xrange(21)])

Na escolha colocar todos os caracteres aceitáveis.

Enquanto estiver usando uma função hash real, como SHA1 também vai obter resultados agradáveis ?? se usado corretamente , a complexidade adicional e consumo de CPU não parece justificado para suas necessidades. Você só quer uma seqüência aleatória.

Por que não dar os primeiros 21 caracteres do md5 ou hash SHA1?

O módulo base64 pode fazer a codificação URL-safe. Então, se necessário, em vez de

u.bytes.encode("base64")

você poderia fazer

import base64

token = base64.urlsafe_b64encode(u.bytes)

e, convenientemente, para converter de volta

u = uuid.UUID(bytes=base64.urlsafe_b64decode(token))

caracteres ou bytes? Se demorar cordas arbitrárias, você pode apenas usar os bytes e não se preocupar se expandindo para caracteres legíveis (para o qual base64 seria melhor do que hex de qualquer maneira).

MD5 gera 16 caracteres se você não usar a expansão hexadecimal do mesmo. SHA1 gera 20 sob a mesma condição.

>>> import hashlib
>>> len(hashlib.md5('foobar').digest())
16
>>> len(hashlib.sha1('foobar').digest())
20

Poucos bytes extras são necessários depois disso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top