Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Виды кибератак и защита в веб-приложениях
Секурность — критичный аспект разработки. Как Python разработчик с 10+ лет опыта, я сталкивался с различными типами атак и способами защиты. Давайте разберёмся в наиболее распространённых.
1. SQL Injection (SQL-инъекция)
Суть: Злоумышленник вставляет SQL код в пользовательский ввод.
# ❌ УЯЗВИМО — прямая подстановка
username = request.GET.get('username')
query = f"SELECT * FROM users WHERE username = '{username}'"
results = db.execute(query)
# Атака: username = "admin' OR '1'='1
# Запрос станет: SELECT * FROM users WHERE username = 'admin' OR '1'='1'
# Вернёт всех пользователей!
# ✅ ЗАЩИТА — параметризованные запросы
username = request.GET.get('username')
query = "SELECT * FROM users WHERE username = %s"
results = db.execute(query, [username])
# Django ORM защищает автоматически:
user = User.objects.get(username=username) # ✅ Безопасно
# SQLAlchemy с параметрами:
from sqlalchemy import text
result = db.execute(
text("SELECT * FROM users WHERE username = :username"),
{"username": username}
)
Практическая защита:
# 1. Используй ORM (Django ORM, SQLAlchemy)
User.objects.filter(username=username) # ✅
# 2. Параметризованные запросы
db.execute("SELECT * FROM users WHERE username = ?", [username]) # ✅
# 3. Избегай string formatting
# query = f"SELECT * FROM users WHERE username = '{username}'" # ❌
# query = "SELECT * FROM users WHERE username = %s" # ✅
2. Cross-Site Scripting (XSS)
Суть: Вставка JavaScript кода в HTML, который выполняется в браузере другого пользователя.
# ❌ УЯЗВИМО — без экранирования HTML
from django.shortcuts import render
def show_comment(request):
comment = request.GET.get('comment')
# Атака: comment = "<script>alert('Hacked')</script>"
return render(request, 'comment.html', {'comment': comment})
# HTML template (уязвимо):
# <p>{{ comment }}</p> # Скрипт выполнится!
# ✅ ЗАЩИТА — экранирование в шаблонах
# Django шаблоны экранируют по умолчанию
# <p>{{ comment }}</p> # Безопасно — скрипт покажется как текст
# Если нужно вывести HTML (доверяемый):
# <p>{{ comment|safe }}</p> # Будьте осторожны!
# ✅ Явное экранирование в Python
from django.utils.html import escape
safe_comment = escape(comment)
return render(request, 'comment.html', {'comment': safe_comment})
Защита в JSON ответах:
# ✅ JSON автоматически экранирует опасные символы
from django.http import JsonResponse
comment = "<script>alert('XSS')</script>"
return JsonResponse({'comment': comment}) # JSON экранирует автоматически
# Ответ:
# {"comment": "<script>alert('XSS')</script>"}
# Браузер не выполнит скрипт в JSON, это просто строка
Content Security Policy (CSP):
# Django middleware для защиты
from django.middleware.security import SecurityMiddleware
# settings.py
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
# ...
]
# Или явно в ответе
from django.http import HttpResponse
response = HttpResponse(content)
response['Content-Security-Policy'] = "script-src 'self'"
# Разрешить скрипты только с того же домена
3. Cross-Site Request Forgery (CSRF)
Суть: Злоумышленник заставляет пользователя выполнить действие от его имени без его согласия.
# ❌ УЯЗВИМО
# HTML в браузере пользователя:
# <img src="http://bank.com/transfer?to=attacker&amount=1000" />
# Когда пользователь посещает вредоносный сайт,
# скрытый img тег отправляет запрос к банку от его имени!
# ✅ ЗАЩИТА — CSRF токены в Django
# template.html
{% csrf_token %}
<form method="POST">
<input name="amount" value="100">
<button type="submit">Transfer</button>
</form>
# Django автоматически генерирует токен и проверяет его
# POST /transfer/ должен содержать правильный токен
# settings.py
MIDDLEWARE = [
'django.middleware.csrf.CsrfViewMiddleware', # ✅ Включена по умолчанию
]
# Для API с JSON
from django.middleware.csrf import csrf_exempt
@csrf_exempt # ❌ Не рекомендуется
def api_endpoint(request):
# ...
# Лучше — использовать SameSite cookies
response.set_cookie(
'sessionid',
value=session_id,
samesite='Strict' # ✅ Браузер не отправит при cross-site запросе
)
4. SQL Injection через ORM
Даже ORM может быть уязвима при неправильном использовании:
# ❌ УЯЗВИМО — использование raw() с format strings
query_str = f"SELECT * FROM users WHERE username = {username}"
User.objects.raw(query_str) # Уязвимо!
# ✅ ЗАЩИТА — параметры в raw()
User.objects.raw('SELECT * FROM users WHERE username = %s', [username])
# ❌ УЯЗВИМО — filter с динамическими ключами
filter_key = f"{request.GET.get('field')}__icontains"
User.objects.filter(**{filter_key: value}) # Потенциально опасно
# ✅ ЗАЩИТА — whitelist разрешённых полей
ALLOWED_FIELDS = ['username', 'email', 'first_name']
field = request.GET.get('field')
if field not in ALLOWED_FIELDS:
raise ValueError("Invalid field")
User.objects.filter(**{f"{field}__icontains": value})
5. Command Injection
Суть: Вставка системных команд через пользовательский ввод.
# ❌ УЯЗВИМО — использование shell=True
import subprocess
username = request.GET.get('username')
result = subprocess.run(
f"grep {username} /etc/passwd",
shell=True # ❌ ОПАСНО!
)
# Атака: username = "; rm -rf /; #"
# Команда станет: grep ; rm -rf /; # /etc/passwd
# Удалит весь сервер!
# ✅ ЗАЩИТА — передавать аргументы списком
result = subprocess.run(
['grep', username, '/etc/passwd'],
shell=False, # ✅ Аргументы не интерпретируются как shell код
capture_output=True,
text=True
)
6. Path Traversal (Directory Traversal)
Суть: Обращение к файлам вне предполагаемой директории через ../.
# ❌ УЯЗВИМО
def download_file(request):
filename = request.GET.get('file')
filepath = f"/uploads/{filename}"
# Атака: filename = "../../etc/passwd"
# filepath станет: /uploads/../../etc/passwd = /etc/passwd
with open(filepath, 'rb') as f:
return HttpResponse(f.read())
# ✅ ЗАЩИТА — использовать os.path.normpath и проверку
import os
from pathlib import Path
def download_file(request):
filename = request.GET.get('file')
base_dir = Path('/uploads')
filepath = (base_dir / filename).resolve()
# Проверка — путь должен быть внутри base_dir
if not str(filepath).startswith(str(base_dir)):
raise PermissionError("Access denied")
with open(filepath, 'rb') as f:
return HttpResponse(f.read())
7. Broken Authentication
Слабые пароли и плохая аутентификация:
# ❌ ПЛОХО
def login(request):
username = request.POST.get('username')
password = request.POST.get('password')
# Хранение пароля в plaintext
user = User.objects.get(username=username, password=password) # ❌
# Нет защиты от brute force
# Нет двухфакторной аутентификации
# ✅ ПРАВИЛЬНО
from django.contrib.auth import authenticate, login
from django.contrib.auth.models import User
from django_ratelimit.decorators import ratelimit
@ratelimit(key='ip', rate='5/m') # 5 попыток в минуту
def login(request):
username = request.POST.get('username')
password = request.POST.get('password')
# Django хеширует пароли автоматически
user = authenticate(username=username, password=password) # ✅
if user is not None:
login(request, user) # Создаёт защищённую сессию
return redirect('home')
else:
return render(request, 'login.html', {'error': 'Invalid credentials'})
8. Sensitive Data Exposure
Утечка конфиденциальных данных:
# ❌ ПЛОХО
def get_user_info(request):
user = User.objects.get(id=request.GET.get('user_id'))
return JsonResponse({
'username': user.username,
'email': user.email,
'password_hash': user.password, # ❌ Никогда!
'ssn': user.ssn, # ❌ Конфиденциальная информация
})
# ✅ ПРАВИЛЬНО — использовать Serializer с read_only
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'username', 'email']
extra_kwargs = {
'password': {'write_only': True}, # Не выводить
'ssn': {'write_only': True}, # Не выводить
}
def get_user_info(request):
user = User.objects.get(id=request.GET.get('user_id'))
serializer = UserSerializer(user)
return JsonResponse(serializer.data) # Только разрешённые поля
# Также используй HTTPS
SECURE_SSL_REDIRECT = True # Редирект HTTP на HTTPS
SESSION_COOKIE_SECURE = True # Cookie только через HTTPS
CSRF_COOKIE_SECURE = True # CSRF cookie только через HTTPS
9. Insecure Deserialization
Опасность десериализации неверенных данных:
# ❌ ОЧЕНЬ ОПАСНО — pickle!
import pickle
data = request.GET.get('data')
object = pickle.loads(data) # ❌ Выполнит любой Python код!
# Атака может выполнить произвольный код на сервере
# ✅ ЗАЩИТА — использовать JSON
import json
data = request.GET.get('data')
object = json.loads(data) # ✅ Безопасно, только структура данных
# Если нужна сложная сериализация:
from pydantic import BaseModel
class DataModel(BaseModel):
field1: str
field2: int
object = DataModel(**json.loads(data)) # ✅ Валидирует и типизирует
10. Security Headers
Добавь security headers в Django:
# settings.py
SECURE_HSTS_SECONDS = 31536000 # 1 год
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_BROWSER_XSS_FILTER = True # X-XSS-Protection
X_FRAME_OPTIONS = 'DENY' # X-Frame-Options
SECURE_CONTENT_SECURITY_POLICY = {
'default-src': ("'self'",),
'script-src': ("'self'", 'cdn.example.com'),
'style-src': ("'self'", "'unsafe-inline'"),
}
# Ответы будут содержать:
# Strict-Transport-Security
# X-Frame-Options: DENY
# Content-Security-Policy
# X-Content-Type-Options: nosniff
Чеклист безопасности
- SQL запросы параметризованы (ORM или %s)
- HTML экранирован в шаблонах
- CSRF токены включены
- HTTPS используется везде
- Пароли хешированы (Django hashers)
- Rate limiting на чувствительных endpoints
- Нет конфиденциальных данных в API ответах
- Security headers установлены
- Зависимости обновлены (pip check, safety)
- Логирование безопасности событий
- Регулярный security audit кода
Заключение
Основные виды атак, о которых должен знать каждый разработчик:
- SQL Injection → параметризованные запросы
- XSS → экранирование HTML
- CSRF → CSRF токены
- Command Injection → не использовать shell=True
- Path Traversal → проверка путей
- Broken Auth → Django authenticate
- Data Exposure → правильный serializer
- Deserialization → JSON вместо pickle
- Race Conditions → atomic transactions
- Security Headers → HTTP headers
Защита от атак — это не когда-нибудь, а каждый день разработки.