Модуль 25

Безпека Django-додатків

Ось готовий урок, створений спеціально для тебе у стилі David Malan. Вмикай уяву, ніби ти зараз в аудиторії Sanders Theatre в Гарварді!


🛡️ Тема уроку: Безпека Django-додатків

1. 🔥 Вступ: Чому ми не залишаємо ключі під килимком?

Привіт, друзі! 👋

Уявіть собі таку ситуацію. Ви збудували неймовірний будинок. У ньому зручні меблі, розумне світло, повний холодильник їжі. Ви запрошуєте друзів на вечірку. Але є одна деталь: ви забули поставити вхідні двері.

Будь-хто з вулиці може зайти, з’їсти ваш бутерброд, переставити меблі або, що гірше, винести телевізор.

З веб-додатками — те саме. Ви можете написати геніальний код, створити красивий інтерфейс, але якщо ви проігнорували безпеку — ваш додаток це "прохідний двір".

Скажіть мені чесно: Ви б ввели номер своєї кредитної картки на сайті, який написав ваш сусід-першокурсник за одну ніч?

Отож-бо.

Сьогодні ми говоримо про Безпеку в Django. Чому саме Django? Тому що розробники цього фреймворку дотримуються філософії "batteries included" (все включено), і одна з найпотужніших "батарейок" — це вбудована система безпеки.

Наша мета сьогодні: Навчитися не залишати ключі під килимком і зрозуміти, як Django допомагає нам захищатися від "поганих хлопців" в інтернеті.


2. 🧠 Теоретична база: Три вершники апокаліпсису

Давайте не будемо занурюватися в нудні стандарти ISO, а розберемося інтуїтивно. У світі веб-безпеки є три найпопулярніші способи зломати ваш сайт. Django вміє з ними боротися, якщо ви йому не заважаєте.

1. SQL Injection (SQL-ін'єкція) — "Шпигун у ресторані"

Аналогія: Ви в ресторані. Ви пишете на папірці замовлення для офіціанта: "Принеси мені борщ". Офіціант несе папірець кухарю. Але уявіть, що хитрий хакер пише: "Принеси мені борщ; А ТАКОЖ віддай всі гроші з каси". Якщо кухар (база даних) наївний, він зробить і те, і інше.

Як це працює: Зловмисник вводить SQL-код у поле вводу (наприклад, логін), і база даних виконує цей код. Захист Django: Django ORM (Object-Relational Mapping). Він автоматично "екранує" (знешкоджує) все, що вводить користувач, перш ніж відправити запит у базу.

2. XSS (Cross-Site Scripting) — "Отруйний графіті"

Аналогія: Хакер малює на стіні вашого під'їзду (вашого сайту) оголошення: "Безкоштовні айфони тут!". Ваші сусіди (користувачі) вірять, йдуть туди й втрачають гаманці.

Як це працює: Хакер вставляє шкідливий JavaScript-код у коментар чи повідомлення на форумі. Коли інші користувачі відкривають сторінку, цей скрипт запускається в їхньому браузері і краде їхні дані (cookies, сесії). Захист Django: Шаблонізатор Django за замовчуванням не виконує те, що введено користувачем, а просто показує це як текст.

3. CSRF (Cross-Site Request Forgery) — "Підроблений підпис"

Аналогія: Хакер підсовує вам документ на підпис, прикривши текст іншим папірцем. Ви думаєте, що підписуєте доставку піци, а насправді — переписуєте квартиру на хакера.

Як це працює: Зловмисник створює фейкову форму на своєму сайті, яка відправляє запит на ваш банківський сайт, де ви зараз залогінені. Захист Django: CSRF-токен. Це як секретне рукостискання. Кожна форма, яку видає Django, має унікальний код. Якщо сервер отримує форму без цього коду — він її викидає.


3. 🧪 Приклади: Від небезпечного до надійного

Сценарій №1: Пошук користувача (SQL Injection)

Припустимо, ми шукаємо користувача за іменем.

🔴 Поганий код (ніколи так не робіть!):

def search_user(request):
    username = request.GET.get('name')
    # Ми склеюємо рядки прямо в SQL. Це дірка в безпеці!
    query = f"SELECT * FROM auth_user WHERE username = '{username}'"
    cursor.execute(query)
    # ...

Запитання до вас: Що буде, якщо я введу ім'я ' OR '1'='1? Відповідь: Запит перетвориться на SELECT * FROM auth_user WHERE username = '' OR '1'='1'. Умова 1=1 завжди істинна. База даних поверне всіх користувачів!

🟢 Хороший код (Django Style):

def search_user(request):
    username = request.GET.get('name')
    # Використовуємо ORM. Django сам перевірить, що username — це просто текст.
    users = User.objects.filter(username=username)
    # ...

Сценарій №2: Відображення коментаря (XSS)

Користувач залишає коментар: <script>alert('Hacked!');</script>.

🔴 Поганий код (в шаблоні HTML):

<!-- Фільтр safe каже Django: "Вір цьому тексту, він безпечний". 
     Це брехня! Не робіть цього з даними користувача. -->
<div>
    {{ comment.text|safe }}
</div>

Результат: У кожного, хто зайде на сторінку, вискочить вікно "Hacked!".

🟢 Хороший код:

<!-- Django автоматично перетворить <script> на безпечні символи &lt;script&gt; -->
<div>
    {{ comment.text }}
</div>

Результат: Користувачі просто побачать текст <script>... на екрані, але код не виконається.


Сценарій №3: Форма переказу грошей (CSRF)

Ви робите форму для переказу коштів.

🔴 Поганий код (форма в шаблоні):

<form method="post" action="/transfer/">
    <input type="text" name="amount">
    <button type="submit">Надіслати</button>
</form>

Проблема: Інший сайт може створити таку ж форму і відправити POST-запит на /transfer/ від вашого імені.

🟢 Хороший код:

<form method="post" action="/transfer/">
    {% csrf_token %}  <!-- Ось наш щит! -->
    <input type="text" name="amount">
    <button type="submit">Надіслати</button>
</form>

Результат: Django згенерує приховане поле з унікальним ключем. Якщо запит прийде без нього — помилка 403 Forbidden.


4. 🛠 Практична частина: Час захищати фортецю!

Спробуйте вирішити ці завдання. Уявіть, що ви проводите аудит безпеки.

Завдання 1: Знайди шпигуна У коді нижче є вразливість. Яка саме?

def profile_view(request):
    user_id = request.GET.get('id')
    # raw() дозволяє писати сирий SQL
    user = User.objects.raw('SELECT * FROM auth_user WHERE id = %s' % user_id)
    return render(request, 'profile.html', {'user': user})

Завдання 2: Лагодження дверей У вас є шаблон, який виводить біографію користувача. Розробник хотів, щоб користувачі могли виділяти текст жирним (<b>), але випадково дозволив і скрипти.

{{ user.bio|safe }}

Завдання: Як змінити цей код, щоб він був безпечним, але все ще дозволяв тільки просте форматування? (Підказка: погугліть django-bleach або стандартні фільтри, але найпростіше рішення — просто прибрати safe).

Завдання 3: DEBUG = True Ви залили сайт на реальний сервер (Production), але залишили в налаштуваннях settings.py:

DEBUG = True
ALLOWED_HOSTS = []

Питання: Чому це катастрофа? Що побачить хакер, якщо викличе помилку на сайті?

Завдання 4: Міні-кейс Ви створюєте форму для зміни пароля. 1. Який метод HTTP ви повинні використати (GET чи POST)? Чому? 2. Який тег шаблону обов’язково треба додати всередину <form>?


5. 💡 Мислення як у розробника

Ось секрет, який відрізняє новачків від профі:

Новачок думає: "Як зробити так, щоб це працювало?" Профі думає: "Як це можуть зламати?"

Типові помилки новачків:

  1. Сліпа довіра: Думати, що користувачі будуть вводити тільки правильні дані. Спойлер: ніколи не довіряйте вводу користувача (Never Trust User Input).
  2. Винахід велосипеда: Писати власну систему шифрування паролів. Ні! Використовуйте те, що є в Django (make_password, check_password).
  3. Зберігання секретів у коді: Заливати SECRET_KEY або паролі від бази даних прямо в GitHub.

Як думає Senior:

  • "Я використовую змінні оточення (Environment Variables) для секретів".
  • "Я завжди оновлюю Django до останньої версії, бо там є патчі безпеки".
  • "Я знаю, що безпека — це не стан, а процес".

6. 🧩 Підсумок

Отже, що ми сьогодні дізналися?

  1. SQL Injection — це спроба керувати вашою базою даних через поля вводу. Ліки: Django ORM.
  2. XSS — це спроба виконати чужий код у браузері ваших користувачів. Ліки: Автоматичне екранування шаблонів.
  3. CSRF — це спроба діяти від вашого імені без вашого відома. Ліки: {% csrf_token %}.

Тепер ви не просто пишете код, який працює. Ви пишете код, який тримає удар. Ви стали охоронцями даних своїх користувачів. Це велика відповідальність, але я знаю, що ви впораєтесь!

А наступного разу... Ми поговоримо про те, як зробити наш безпечний додаток ще й швидким. Ми заглянемо у світ Кешування та Оптимізації. Чи готові ви розігнати свій код до швидкості світла?

Побачимось на наступній лекції! Це був CS50. 💻❤️