Flask — це веб-фреймворк, який дозволяє розробникам швидко і легко створювати легкі веб-додатки. Це мікрофреймворк, що дає змогу швидко розробляти веб-додатки.
Сучасні вебсайти та веб-додатки приймають вхідні дані від користувачів, що є важливою частиною їх роботи. Звичні типи вхідних даних — це зображення, відео та PDF-файли. Однак завантаження файлів несе в собі безпекові загрози та ризики. У цій статті ми обговоримо ці ризики і способи їх мінімізації.
Що таке вразливості при завантаженні файлів?
Вразливості при завантаженні файлів виникають, коли бекенд система не перевіряє ім'я файлу, тип та вміст. Ці вразливості можуть спричиняти значні ризики для додатків, систем та даних користувачів, оскільки дозволяють зловмисникам завантажувати шкідливі файли. Якщо ці вразливості не контролюються, вони можуть призвести до серйозних порушень безпеки. Ось деякі основні ризики, пов'язані з вразливостями при завантаженні файлів:
- Це дозволяє зловмисникам виконати віддалений код (Remote Code Execution).
- Зловмисник може здійснити атаку "відмова в обслуговуванні" (Denial of Service).
- Зловмисники можуть обійти аутентифікацію чи авторизацію.
- Зловмисник може перезаписати критичні файли.
Завантаження файлів у Flask-додатку
Завантаження файлів у Flask-додатку досить просте. Офіційна документація чітко пояснює, що знаходиться в
з тегом enctype=multipart/form-data
. Flask-додаток може отримати файл з об'єкта запиту, зловивши його з словника files. Проте простота реалізації не гарантує безпеку. Розглянемо базовий приклад обробки завантаження файлів у Flask:
from flask import Flask, request, redirect
from werkzeug.utils import secure_filename
app = Flask(__name__)
@app.route('/', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return redirect(request.url)
# requested file
file = request.files['file']
filename = secure_filename(file.filename)
file.save(os.path.join('/path/to/the/uploads', filename))
return 'File successfully uploaded'
Як захистити Flask-додаток від вразливостей при завантаженні файлів
Перевірка імені файлу
Важливо правильно перевіряти ім'я файлу, щоб уникнути атак через проходження шляху (path traversal). Ці вразливості дозволяють зловмисникам читати або записувати довільні файли на сервері. Наприклад, уявімо ситуацію, коли користувач завантажує файл з таким іменем:
filename="../../../../etc/passwd"
Якщо шлях вірний, файл буде збережено в системі додатку поза кореневою директорією проєкту. Щоб уникнути цієї проблеми, можна використовувати функцію secure_filename
, яка очищає та забезпечує безпеку імен файлів перед їх збереженням на сервері.
secure_filename('../../../../etc/passwd') #'etc_passwd'
Фільтрація за розширенням файлів
Дуже простий, але ефективний метод перевірки — це перевірка розширення файлу. Обмеження типів файлів, які користувач може завантажити, може зменшити ризик завантаження шкідливих файлів. Однак цей метод не є надійним. Зловмисник може обійти це обмеження, знайшовши недоліки в налаштуваннях веб-сервера, коли він обробляє файли.
app.config['ALLOWED_EXTENSIONS'] = ['.txt', '.jpg', '.png', '.gif']
def allowed_file(filename):
return os.path.splitext(filename)[-1] in current_app.config['ALLOWED_EXTENSIONS']
Обмеження розміру файлів
Великі файли можуть погіршити швидкість завантаження вебсайту. Обмеження розміру завантажених файлів може запобігти атаці типу "відмова в обслуговуванні" (Denial of Service). Flask має вбудовану опцію конфігурації під назвою MAX_CONTENT_LENGTH
, яка запобігає завантаженню файлів, що перевищують встановлений ліміт.
app.config['MAX_CONTENT_LENGTH'] = 24 * 1024 * 1024 # 24 мегабайти
Перевірка типу контенту
Перевірка типу контенту є більш надійним способом перевірки типу файлу, ніж перевірка за розширенням файлу.
Доброю практикою є використання як перевірки розширення файлу, так і перевірки типу контенту (Content-Type). Перевірка типу контенту валідовує MIME тип завантаженого файлу. Існує кілька способів досягнення перевірки типу контенту в Python.
- Бібліотека
magic
(з пакетуpython-magic
) використовує сигнатури файлів (магічні числа) для визначення типів файлів. Це надійніше, ніж проста перевірка розширення файлу чи MIME типу, оскільки вона дивиться на фактичний вміст файлу. - Для перевірки зображень в Python вбудований модуль
imghdr
, який визначає типи зображень, перевіряючи їхні заголовки. (Відмінено з версії 3.11, видалено у версії 3.13.)
import magic
def validate_content_type(file):
mime = magic.from_buffer(file.stream.read(2048), mime=True)
file.stream.seek(0) # Reset file pointer after reading
return mime in ['text/plain', 'image/jpeg', 'application/json']
Висновок
Завантаження файлів користувачами — це звична вимога для сучасних вебсайтів і веб-додатків. Однак для зменшення ризиків, пов'язаних з прийманням файлів від користувачів, необхідно застосовувати надійні заходи безпеки. Використання наведених практик допоможе захистити ваш Flask-додаток, сервер та дані.
Перекладено з: Securing file upload in a Flask Application and preventing path traversal attack