CPython имеет глобальное ограничение на преобразование между int
и str
для смягчения атак типа "отказ в обслуживании". Это ограничение применяется только к десятичным или другим системам счисления, не равным степени двойки. Шестнадцатеричные, восьмеричные и двоичные преобразования не ограничены. Лимит можно настроить.
Новое в Python 3.11.
Тип int
в CPython - это число произвольной длины, хранящееся в двоичной форме (обычно известное как "bignum"). Не существует алгоритма, который может преобразовать строку в двоичное целое число или двоичное целое число в строку за линейное время, если только основание не является степенью числа 2. Даже самые известные алгоритмы для основания 10 имеют субквадратичную сложность. Преобразование большого значения, такого как int('1' * 500_000)
, может занять больше секунды на быстром процессоре.
Ограничение размера преобразования предлагает практичный способ избежать CVE-2020-10735
.
Ограничение применяется к количеству цифровых символов во входной или выходной строке, когда будет задействован алгоритм нелинейного преобразования. Подчеркивания и знаки не учитываются при подсчете лимита.
Когда операция превышает лимит, возникает ошибка ValueError
:
>>> import sys >>> sys.set_int_max_str_digits(4300) # Illustrative, this is the default. >>> _ = int('2' * 5432) # Traceback (most recent call last): # ... # ValueError: Exceeds the limit (4300) for integer string conversion: # value has 5432 digits; use sys.set_int_max_str_digits() to increase the limit. >>> i = int('2' * 4300) >>> len(str(i)) # 4300 >>> i_squared = i*i >>> len(str(i_squared)) # Traceback (most recent call last): # ... # ValueError: Exceeds the limit (4300) for integer string conversion: # value has 8599 digits; use sys.set_int_max_str_digits() to increase the limit. >>> len(hex(i_squared)) # 7144 # Шестнадцатеричное число не ограничено. >>> assert int(hex(i_squared), base=16) == i*i
Ограничение по умолчанию составляет 4300 цифр, как указано в sys.int_info.default_max_str_digits
. Минимальное ограничение, которое можно настроить, составляет 640 цифр, как указано в sys.int_info.str_digits_check_threshold
.
Проверка:
>>> import sys >>> assert sys.int_info.default_max_str_digits == 4300, sys.int_info >>> assert sys.int_info.str_digits_check_threshold == 640, sys.int_info >>> msg = int('578966293710682886880994035146873798396722250538762761564' ... '9252925514383915483333812743580549779436104706260696366600' ... '571186405732').to_bytes(53, 'big')
Ограничение распространяется только на потенциально медленные преобразования между int
и str
или bytes
:
int(string)
с базой по умолчанию base=10
.int(string, base)
для всех оснований, которые не являются степенью числа 2.str(integer)
.repr(integer)
.f'{integer}'
, '{}'.format(integer)
или b'%d' % integer
.Ограничения не распространяются на функции с линейным алгоритмом:
int(string, base)
с основанием 2, 4, 8, 16, or 32.int.from_bytes()
и int.to_bytes()
.hex()
, oct()
, bin()
.str
в float
.str
в decimal.Decimal
.Ожидается, что значение по умолчанию sys.int_info.default_max_str_digits
подойдет для большинства приложений. Если приложению требуется другое ограничение, то необходимо установить его из основной точки входа с помощью независимого от версии кода Python, поскольку эти API-интерфейсы были добавлены в выпусках исправлений безопасности в версиях Python до 3.11.
Пример:
import sys if hasattr(sys, "set_int_max_str_digits"): upper_bound = 68000 lower_bound = 4004 current_limit = sys.get_int_max_str_digits() if current_limit == 0 or current_limit > upper_bound: sys.set_int_max_str_digits(upper_bound) elif current_limit < lower_bound: sys.set_int_max_str_digits(lower_bound)
Если нужно полностью отключить его, установите его на 0.
Перед запуском Python можно использовать переменную среды или флаг командной строки интерпретатора для настройки ограничения:
PYTHONINTMAXSTRDIGITS=640
в Python3, установит ограничение на 640, или PYTHONINTMAXSTRDIGITS=0
Python3, отключит ограничение.python3 -X int_max_str_digits = 640
, установит ограничение на 640.Атрибут sys.flags.int_max_str_digits
содержит значение PYTHONINTMAXSTRDIGITS
или -X int_max_str_digits
. Если установлены и env var
, и опция -X
, то опция -X
имеет приоритет. Значение -1
указывает на то, что оба значения не установлены, поэтому во время инициализации использовалось значение sys.int_info.default_max_str_digits
.
Из кода можно проверить текущий лимит и установить новый, используя эти системные API:
sys.get_int_max_str_digits()
и sys.set_int_max_str_digits()
являются геттером и сеттером для ограничения на уровне интерпретатора. У субинтерпретаторов есть свой предел.Информацию о значении по умолчанию и минимуме можно найти в sys.int_info
:
sys.int_info.default_max_str_digits
- это скомпилированное ограничение по умолчанию.sys.int_info.str_digits_check_threshold
- это наименьшее допустимое значение ограничения (кроме 0, которое отключает его).Внимание Установка нижнего предела может привести к проблемам. Хотя и редко, существует код, который содержит целые константы в десятичном виде в своем источнике, которые превышают минимальный порог. Следствием установки ограничения является то, что исходный код Python, содержащий десятичные целые литералы длиннее ограничения, столкнется с ошибкой во время синтаксического анализа, обычно во время запуска, во время импорта или даже во время установки - в любое время, когда обновленный файл
.pyc
еще не существует для кода. Обходной путь для источника, который содержит такие большие константы, состоит в том, чтобы преобразовать их в шестнадцатеричную форму0x
, поскольку она не имеет ограничений.
Тщательно протестируйте свое приложение, если используете низкий лимит. Убедитесь, что тесты выполняются с заранее установленным ограничением через среду или флаг, чтобы оно применялось во время запуска и даже на любом этапе установки, который может вызывать Python для предварительной компиляции исходных кодов .py
в файлы .pyc
.