OWASP Top 10 — 10 Найнебезпечніших Вразливостей¶
OWASP (Open Web Application Security Project) — некомерційна організація, що щороку публікує список 10 найпоширеніших вразливостей у вебзастосунках. Це "чорний список" атак, які ти зобов'язаний знати.
Аналогія: OWASP Top 10 — це як ТОП-10 способів пограбування банку. Охоронці банку зобов'язані знати всі ці способи щоб їх запобігти.
A01 — Broken Access Control (Порушений Контроль Доступу)¶
Найпоширеніша вразливість у 2021-2023 рр.
Що це: Юзер може виконати дії або отримати дані, до яких не повинен мати доступу.
Приклади:
- Аліса змінює URL /notes/42/edit/ на /notes/43/edit/ і редагує нотатку Боба
- URL /admin/ доступний без перевірки is_staff
- API повертає список всіх юзерів замість тільки свого профілю
Django захист:
# ПОГАНО:
note = get_object_or_404(Note, pk=pk) # будь-хто може отримати будь-яку нотатку
# ДОБРЕ:
note = get_object_or_404(Note, pk=pk, user=request.user) # тільки свої
У нашому проєкті:
- @login_required на всіх views
- get_object_or_404(..., user=request.user) у note_edit, note_delete тощо
- Групи: Q(user=user) | Q(group__in=user_groups) — видно тільки своє і групове
A02 — Cryptographic Failures (Криптографічні Помилки)¶
Що це: Збереження або передача чутливих даних без належного шифрування.
Приклади:
- Пароль зберігається у відкритому вигляді: password = "secret123" у БД
- HTTP замість HTTPS → паролі передаються відкритим текстом
- Слабкий алгоритм хешування (MD5, SHA-1) для паролів
Django захист:
# Django автоматично хешує паролі через PBKDF2:
user.set_password("new_password")
# → pbkdf2_sha256$720000$salt$hash (зберігається у БД)
# Ніколи не зберігай:
user.raw_password = "secret" # НІКОЛИ!
Note.objects.create(content=request.POST['secret']) # без шифрування — погано
Production налаштування:
# settings.py (розкоментуй у production):
SESSION_COOKIE_SECURE = True # cookie тільки по HTTPS
CSRF_COOKIE_SECURE = True
SECURE_SSL_REDIRECT = True # HTTP → автоматичний редирект на HTTPS
A03 — Injection (Ін'єкція)¶
Що це: Атакер вставляє шкідливий код у запит, який виконується на сервері.
Типи: - SQL Injection — шкідливий SQL у запиті - XSS — шкідливий JavaScript у HTML - Command Injection — виконання системних команд
SQL Injection¶
# НЕБЕЗПЕЧНО — конкатенація рядків:
user_input = "'; DROP TABLE notes; --"
query = f"SELECT * FROM notes WHERE title = '{user_input}'"
# ↑ Цей код ВИДАЛЯЄ всю таблицю notes!
# БЕЗПЕЧНО — Django ORM параметризує запити автоматично:
notes = Note.objects.filter(title=user_input)
# → SQL: SELECT * FROM notes WHERE title = %s (з escaped параметром)
XSS (Cross-Site Scripting)¶
<!-- НЕБЕЗПЕЧНО — без екранування: -->
<div>{{ note.content|safe }}</div>
<!-- Якщо content = "<script>document.cookie</script>" → виконається у браузері -->
<!-- БЕЗПЕЧНО — Django екранує HTML автоматично: -->
<div>{{ note.content }}</div>
<!-- Виведе: <script>document.cookie</script> (безпечно) -->
Django захист від XSS:
- Шаблонний рушій {{ variable }} екранує все автоматично
- Використовуй |safe тільки якщо ВПЕВНЕНИЙ що контент безпечний (не user input!)
A04 — Insecure Design (Небезпечне Проєктування)¶
Що це: Архітектурні рішення з вбудованими вразливостями.
Приклади: - Форма реєстрації не має захисту від bot-реєстрацій (потрібна CAPTCHA або rate limiting) - Password reset надсилає пароль відкритим текстом у листі (замість токена) - Немає обмеження на кількість спроб входу (можливий brute-force)
Django рішення:
# Rate limiting (обмеження кількості запитів):
# pip install django-axes
# settings.py:
INSTALLED_APPS += ['axes']
AXES_FAILURE_LIMIT = 5 # 5 невдалих спроб → блокування
AXES_COOLOFF_TIME = 1 # блокування на 1 годину
# Або: django-ratelimit
from ratelimit.decorators import ratelimit
@ratelimit(key='ip', rate='5/m', block=True)
def login_view(request):
...
A05 — Security Misconfiguration (Неправильна Конфігурація Безпеки)¶
Що це: Небезпечні налаштування залишені за замовчуванням або встановлені помилково.
Приклади:
- DEBUG = True в production → витік SECRET_KEY, стектрейсів, SQL-запитів
- Адмін-панель /admin/ за стандартним URL (легко знайти)
- Стандартні паролі БД (admin/admin)
Django налаштування:
# settings.py — обов'язково в production:
DEBUG = False # ← НІКОЛИ True в production!
SECRET_KEY = os.environ['SECRET_KEY'] # ← зберігай у .env, не в коді!
ALLOWED_HOSTS = ['mysite.com'] # ← конкретні домени, не '*'
X_FRAME_OPTIONS = "DENY" # захист від clickjacking
SECURE_CONTENT_TYPE_NOSNIFF = True # браузер не "вгадує" тип файлу
SESSION_COOKIE_HTTPONLY = True # JS не читає sessionid
A06 — Vulnerable and Outdated Components (Застарілі Компоненти)¶
Що це: Використання бібліотек з відомими вразливостями.
Перевірка Django:
# Перевірити вразливості у залежностях:
pip install pip-audit
pip-audit
# Або через safety:
pip install safety
safety check
# Результат:
# Found vulnerability in Django 3.2.0: CVE-2021-XXXXX
# Upgrade to: Django 3.2.14
Правило:
Регулярно оновлюй Django та всі бібліотеки. Слідкуй за security releases на djangoproject.com.
A07 — Identification and Authentication Failures¶
Що це: Слабка аутентифікація — легкі паролі, відсутність MFA, незахищений password reset.
Приклади: - Дозволений пароль "123456" або "password" - Відсутнє обмеження спроб входу → brute-force атака - Password reset токен дійсний безстроково
Django захист:
# settings.py — валідатори паролів:
AUTH_PASSWORD_VALIDATORS = [
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'OPTIONS': {'min_length': 8}},
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
]
# ↑ Django вже має всі ці валідатори, просто не видаляй їх!
Password Reset токен у Django:
- Токен одноразовий (після першого використання інвалідується)
- Діє 72 години за замовчуванням (PASSWORD_RESET_TIMEOUT = 259200)
A08 — Software and Data Integrity Failures¶
Що це: Довіра до даних або коду без перевірки їх цілісності.
Приклади:
- Завантаження JavaScript бібліотек без перевірки хешу (CDN підміна)
- Django pickle серіалізація у сесіях (вразлива до RCE)
Django захист:
<!-- SRI (Subresource Integrity) — перевірка хешу при завантаженні з CDN: -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
integrity="sha384-..."
crossorigin="anonymous"></script>
A09 — Security Logging and Monitoring Failures¶
Що це: Відсутність логів або моніторингу безпекових подій.
Що треба логувати: - Невдалі спроби входу (brute-force детекція) - Спроби доступу до чужих об'єктів (IDOR спроби) - Зміна прав доступу (хто і кому призначив права) - Видалення даних (хто видалив)
Django логування:
# settings.py:
LOGGING = {
'version': 1,
'handlers': {
'file': {
'class': 'logging.FileHandler',
'filename': 'logs/security.log',
},
},
'loggers': {
'django.security': {
'handlers': ['file'],
'level': 'WARNING',
},
},
}
# views.py — логування підозрілих дій:
import logging
logger = logging.getLogger('django.security')
def note_delete(request, pk):
note = get_object_or_404(Note, pk=pk, user=request.user)
logger.warning(f"User {request.user.pk} deleted note {pk}")
note.delete()
A10 — Server-Side Request Forgery (SSRF)¶
Що це: Атакер змушує сервер робити запити до внутрішніх ресурсів.
Приклад:
# Небезпечна функція "завантажити аватар з URL":
def upload_avatar(request):
url = request.POST.get('avatar_url')
response = requests.get(url) # SSRF!
# Атакер надсилає: url = "http://169.254.169.254/latest/meta-data/"
# → сервер робить запит до AWS metadata API → витік AWS credentials!
Захист:
from urllib.parse import urlparse
ALLOWED_HOSTS_FOR_FETCH = ['i.imgur.com', 'avatars.githubusercontent.com']
def is_safe_url(url):
parsed = urlparse(url)
return parsed.hostname in ALLOWED_HOSTS_FOR_FETCH
def upload_avatar(request):
url = request.POST.get('avatar_url')
if not is_safe_url(url):
raise PermissionDenied
response = requests.get(url)
Підсумок: Django vs OWASP Top 10¶
| # | Вразливість | Django захист |
|---|---|---|
| A01 | Broken Access Control | @login_required + get_object_or_404(..., user=request.user) |
| A02 | Cryptographic Failures | set_password() (PBKDF2), HTTPS settings |
| A03 | Injection | ORM (SQL), {{ var }} автоекранування (XSS) |
| A04 | Insecure Design | django-axes (rate limiting), правильна архітектура |
| A05 | Security Misconfiguration | DEBUG=False, security settings у settings.py |
| A06 | Vulnerable Components | pip-audit, регулярні оновлення |
| A07 | Auth Failures | AUTH_PASSWORD_VALIDATORS, @login_required, MFA |
| A08 | Integrity Failures | SRI для CDN ресурсів |
| A09 | Logging Failures | django.security logger, структуровані логи |
| A10 | SSRF | Whitelist дозволених URL для зовнішніх запитів |