Si je lis bien votre question, vous voulez générer un certain jeton d'identification arbitraire qui doit être 21 caractères max. Est-ce qu'il doit être très résistant aux devinettes? L'exemple que vous avez donné n'est pas "crytographiquement fort" en ce sens qu'il peut être deviné en cherchant bien moins de la moitié de tout l'espace-clé possible. Vous ne dites pas si les caractères peuvent être tous les 256 caractères ASCII, ou si elle doit être limitée à, disons, ASCII imprimable (33-127, inclusivement), ou une plus petite portée.
Il y a un module Python conçu pour UUID s (universaux Unique Identifiers). Vous voulez probablement uuid4 qui génère un UUID aléatoire, et utilise le support de l'OS si disponible (sur Linux, Mac, FreeBSD, et probablement d'autres).
>>> 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 octets aléatoires est très unguessable, et il n'y a pas besoin d'utiliser les 21 octets complet de votre API permet, si tout ce que vous voulez est d'avoir un identifiant opaque unguessable. Si vous ne pouvez pas utiliser des octets bruts comme cela, ce qui est probablement une mauvaise idée car il est plus difficile à utiliser dans les journaux et les autres messages de débogage et plus difficile à comparer à l'oeil, convertir les octets en quelque chose de plus lisible. comme l'utilisation de base 64 codage, le résultat abattu à 21 (ou autre) octets:
>>> u.bytes.encode("base64")
'2UMD5xvkSe+S8kcrxLQobQ==\n'
>>> len(u.bytes.encode("base64"))
25
>>> u.bytes.encode("base64")[:21]
'2UMD5xvkSe+S8kcrxLQob'
>>>
Cela vous donne une chaîne aléatoire de très haute qualité de longueur 21.
Vous pourriez ne pas aimer le '+' ou le '/' qui peut être dans une chaîne de base 64, car sans échappement approprié qui pourrait interférer avec les URL. Puisque vous pensez déjà à utiliser "3 caractères aléatoires", je ne pense pas que cela vous inquiète. Si c'est le cas, vous pourriez remplacer ces caractères par quelque chose d'autre ('-' et '.' Pourraient fonctionner), ou les supprimer s'ils sont présents. Comme d'autres l'ont souligné, vous pouvez utiliser .encode ("hex") et obtenir l'équivalent hexadécimal, mais c'est seulement 4 bits de caractère aléatoire/caractère * 21 caractères max vous donne 84 bits de hasard au lieu de deux fois cela. Chaque bit double votre espace de touches, ce qui rend l'espace de recherche théorique beaucoup plus petit. Par un facteur de 2E24 plus petit.
Votre espace de clés est toujours de taille 2E24, même avec un codage hexadécimal, donc je pense que c'est plus une préoccupation théorique. Je ne m'inquiéterais pas des gens qui font des attaques par force brute contre votre système.
Modifier:
P.S .: La fonction uuid.uuid4 utilise libuuid si elle est disponible. Cela obtient son entropie de os.urandom (si disponible) sinon de l'heure actuelle et l'adresse MAC locale ethernet. Si libuuid n'est pas disponible, la fonction uuid.uuid4 récupère directement les octets de os.urandom (si disponible) sinon elle utilise le module random. Le module random utilise un seed par défaut basé sur os.urandom (si disponible) sinon une valeur basée sur l'heure actuelle. Le sondage a lieu pour chaque appel de fonction, donc si vous n'avez pas os.urandom alors le surcoût est un peu plus grand que ce à quoi vous pourriez vous attendre.
Envoyer un message à la maison? Si vous savez que vous avez os.urandom alors vous pourriez faire
os.urandom(16).encode("base64")[:21]
mais si vous ne voulez pas vous soucier de sa disponibilité utiliser le module UUID.
Vous devez penser SHA1. MD5 est de 32 chiffres hexadécimaux. – kmkaplan