Каков стандартный метод создания одноразового номера в Python?

Может ли кто-нибудь поделиться рекомендациями по созданию одноразового номера для запроса OAuth в Python?


person charliesneath    schedule 08.04.2011    source источник


Ответы (5)


Вот как это делает python-oauth2:

def generate_nonce(length=8):
    """Generate pseudorandom number."""
    return ''.join([str(random.randint(0, 9)) for i in range(length)])

У них также есть:

@classmethod
def make_nonce(cls):
    """Generate pseudorandom number."""
    return str(random.randint(0, 100000000))

Кроме того, существует проблема под названием: «make_nonce недостаточно случайна", в которой предлагается :

def gen_nonce(length):
   """ Generates a random string of bytes, base64 encoded """
   if length < 1:
      return ''
   string=base64.b64encode(os.urandom(length),altchars=b'-_')
   b64len=4*floor(length,3)
   if length%3 == 1:
      b64len+=2
   elif length%3 == 2:
      b64len+=3
   return string[0:b64len].decode()

А также ссылается на CVE-2013-4347. TL;DR, используйте os.urandom или абстрактный интерфейс к нему (SystemRandom).

Мне нравятся мои lambda и мне не нужны не буквенно-цифровые символы, поэтому я использовал это:

lambda length: filter(lambda s: s.isalpha(), b64encode(urandom(length * 2)))[:length]
person A T    schedule 28.01.2015
comment
КСТАТИ. uuid1 создает уникальный ключ на основе хоста и времени: import uuid; uuid.uuid1(). Его можно преобразовать в строку и использовать, если требуется буквенно-цифровой одноразовый номер. Он также имеет компонент времени UTC эпохи, т.е. uuid.uuid1().time вернет длинное целое число. - person radtek; 06.10.2015
comment
Конечно, если вы не хотите, чтобы семя было текущим хостом и временем, вы используете для этого uuid1: docs.python.org/2/library/uuid.html . get_hex() полезен, спасибо! - person radtek; 08.10.2015
comment
Обратите внимание: если вы пытаетесь сгенерировать что-либо с одноразовым номером в имени, ВАЖНО использовать os.urandom() и никогда, никогда random.random или random.randint. В противном случае у вас могут возникнуть серьезные проблемы с безопасностью. - person Aur Saraf; 03.03.2016
comment
@AurSaraf, можете ли вы дополнительно прокомментировать последствия для безопасности при использовании random.randint для создания одноразового номера? Спасибо - person radtek; 03.03.2016
comment
nonce — это слово, придуманное криптографами, которым требовалось новое слово, чтобы однозначно обозначать значение, которое никто не может угадать. (практически, достаточно большое криптографически безопасное случайное целое число). Они творчески используют их в своих протоколах и всегда исходят из того, что никто не может их угадать. random.randint злоумышленникам легко догадаться, что ставит под угрозу безопасность. cigital.com/papers/download/developer_gambling.php - person Aur Saraf; 03.03.2016
comment
Откуда floor(a, b)? В Python3 math.floor принимает один аргумент. - person kevr; 14.06.2021
comment
Да, это странно… В Python 2 был один аргумент, спросите Эрика О'Коннор (вы найдете его по этой ссылке) - person A T; 15.06.2021

Для большинства практических целей это дает очень хороший одноразовый номер:

import uuid
uuid.uuid4().hex
# 'b46290528cd949498ce4cc86ca854173'

uuid4() использует os.urandom(), который является лучшим случайным, который вы можете получить в python.

Nonce следует использовать только один раз, и его трудно предсказать. Обратите внимание, что uuid4() труднее предсказать, чем uuid1(), тогда как более поздние более уникальны в глобальном масштабе. Таким образом, вы можете добиться еще большей силы, комбинируя их:

uuid.uuid4().hex + uuid.uuid1().hex
# 'a6d68f4d81ec440fb3d5ef6416079305f7a44a0c9e9011e684e2c42c0319303d'
person andruso    schedule 30.10.2016
comment
Если вы предполагаете, что uuid1() более глобально уникален, поскольку основан на mac-адресе, то вы должны знать, что mac-адреса на практике далеко не уникальны. Некоторые производители используют один и тот же MAC-адрес для данной партии/модели... Таким образом, исходя из этого предположения, ваше утверждение просто неверно. Напротив. - person comte; 07.06.2020
comment
@comte не только. UUID1 также содержит метку времени. MAC добавляет некоторый уровень уникальности, поскольку НЕКОТОРЫЕ компьютеры в мире имеют разные MAC-адреса. источник - person andruso; 26.08.2020

Хотя этого, вероятно, не существовало на момент создания этого вопроса, Python 3.6 представил секреты модуль, предназначенный для генерации криптографически стойких случайных чисел, подходящих для управления такими данными, как пароли, аутентификация учетной записи, токены безопасности и связанные с ними секреты.

В этом случае можно легко сгенерировать одноразовый номер (здесь строка в кодировке base64):

nonce = secrets.token_urlsafe()

Альтернативы: token_bytes для получения двоичного токена или token_hex, чтобы получить шестнадцатеричную строку.

person gabuzo    schedule 24.01.2019
comment
Недавно я услышал о nonce. Насколько я понимаю, одноразовый номер должен быть целым числом, т.е. числом. Но здесь вы пытаетесь использовать строку в кодировке base64 как nonce. Так что nonce также может быть строкой - person Santhosh; 19.02.2020
comment
Число @SanthoshYedidi nonce зависит от того, как его реализует поставщик токенов (это не является строго частью стандарта JWT). Все провайдеры, которых я видел, с удовольствием используют строки. Важной частью является то, что это одноразовое значение. Цифры, которые только увеличиваются, хороши, но вам нужно решить проблему перезагрузки системы. Обычно проще использовать большую случайную строку. - person Erdős-Bacon; 17.09.2020
comment
да, это правильно, трудно отслеживать приращение - person Santhosh; 17.09.2020

Вот что делает rauth. Здесь нет жестких и быстрых правил. Спецификация не кажется слишком самоуверенной. Ваши ограничения заключаются в том, что значение, являющееся одноразовым номером, должно быть уникальным. В остальном, если поставщик не жалуется, вы можете использовать любой метод, который вам нравится.

person maxcountryman    schedule 28.03.2013
comment
Обратите внимание, что теперь он также вызывает .encode('ascii'), прежде чем передать его sha1. Вероятно, для совместимости с Python 3? - person A T; 28.01.2015

Вот несколько идей, которые я получил для электронной почты. generate_nonce исходит из их кода, но я использую generate_nonce_timestamp, для которого я использовал uuid. Это дает мне случайную буквенно-цифровую строку и отметку времени в секундах:

import random
import time
import uuid


def generate_nonce(length=8):
    """Generate pseudo-random number."""
    return ''.join([str(random.randint(0, 9)) for i in range(length)])


def generate_timestamp():
    """Get seconds since epoch (UTC)."""
    return str(int(time.time()))

def generate_nonce_timestamp():
    """Generate pseudo-random number and seconds since epoch (UTC)."""
    nonce = uuid.uuid1()
    oauth_timestamp, oauth_nonce = str(nonce.time), nonce.hex
    return oauth_nonce, oauth_timestamp

Мне нравится использовать uuid1, так как он генерирует uuid на основе текущего хоста и времени и имеет свойство времени, которое вы можете извлечь, если вам нужно и то, и другое. Для электронной почты вам нужны и временная метка, и одноразовый номер.

Вот что вы получаете:

>>> generate_nonce_timestamp()
('a89faa84-6c35-11e5-8a36-080027c336f0', '136634341422770820')

Если вы хотите удалить -, используйте nonce.get_hex().

uuid1 — генерирует UUID из идентификатора хоста, порядкового номера и текущего времени. Подробнее об uuid.

person radtek    schedule 06.10.2015
comment
См. мой комментарий к @AT о nonces и random.randint (TL; DR: никогда) - person Aur Saraf; 03.03.2016