← Назад к вопросам
Как избежать инъекций в приложении?
2.2 Middle🔥 231 комментариев
#Базы данных (SQL)#Безопасность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Инъекции: защита приложения
Инъекция (Injection) — это атака, когда злоумышленник внедряет вредоносный код в приложение. Это одна из OWASP TOP 10 уязвимостей.
Типы инъекций
1. SQL Injection (SQLi)
Уязвимый код:
# ОПАСНО! Никогда так не делай
user_id = request.args.get("id")
query = f"SELECT * FROM users WHERE id = {user_id}"
results = db.execute(query)
# Злоумышленник передаёт: ?id=1 OR 1=1
# Получится: SELECT * FROM users WHERE id = 1 OR 1=1
# Вернёт всех пользователей!
# Или: ?id=1; DROP TABLE users;--
# Удалит таблицу!
Защита — Parameterized Queries:
# ПРАВИЛЬНО - используй placeholders
user_id = request.args.get("id")
query = "SELECT * FROM users WHERE id = ?"
results = db.execute(query, (user_id,))
# Или с ORM (SQLAlchemy)
user = session.query(User).filter(User.id == user_id).first()
SQL Injection с ORM (безопасно):
from sqlalchemy import text
# НЕПРАВИЛЬНО - конкатенация
query = f"SELECT * FROM users WHERE name = {name}"
# ПРАВИЛЬНО - параметры
query = text("SELECT * FROM users WHERE name = :name")
results = db.execute(query, {"name": name})
# ИЛИ ORM напрямую (самый безопасный вариант)
user = session.query(User).filter(User.name == name).first()
2. Command Injection (OS Command Injection)
Уязвимый код:
import os
# ОПАСНО!
filename = request.args.get("file")
os.system(f"cat {filename}") # Можно внедрить: ; rm -rf /
# Или
subprocess.run(f"ls {directory}", shell=True) # shell=True опасна!
Защита — используй список аргументов:
import subprocess
# ПРАВИЛЬНО - массив аргументов
filename = request.args.get("file")
result = subprocess.run(["cat", filename], capture_output=True)
# Без shell=True
subprocess.run(["ls", directory]) # Не может быть injection
3. XSS (Cross-Site Scripting)
Уязвимый код:
# ОПАСНО!
user_input = request.args.get("comment")
html = f"<p>{user_input}</p>"
# Если user_input = "<script>alert(hacked)</script>"
# Браузер выполнит скрипт!
Защита — экранирование HTML:
from markupsafe import escape
user_input = request.args.get("comment")
html = f"<p>{escape(user_input)}</p>"
# Вывет: <p><script>alert('hacked')</script></p>
# В Jinja2 (Flask/Django) экранирование по умолчанию
# {{ user_input }} # Автоматически экранируется
Защита в JavaScript:
# Используй innerText вместо innerHTML
# JavaScript:
# НЕПРАВИЛЬНО: document.getElementById(comment).innerHTML = userInput;
# ПРАВИЛЬНО: document.getElementById(comment).innerText = userInput;
4. NoSQL Injection
Уязвимый код (MongoDB):
# ОПАСНО!
user_input = request.args.get("name")
user = db.users.find_one({"name": user_input})
# Если user_input = {"$ne": null}
# Запрос станет: {"name": {"$ne": null}}
# Вернёт первого пользователя (любого!)
Защита:
# ПРАВИЛЬНО - валидация типов
user_input = request.args.get("name")
if not isinstance(user_input, str):
raise ValueError("Invalid input")
user = db.users.find_one({"name": user_input})
# Или используй schema validation
from pydantic import BaseModel
class SearchQuery(BaseModel):
name: str # Только строка
query = SearchQuery(name=user_input)
user = db.users.find_one({"name": query.name})
5. LDAP Injection
Уязвимый код:
# ОПАСНО!
username = request.form.get("username")
ldap_filter = f"(uid={username})"
results = ldap_conn.search(ldap_filter)
# Если username = "*)(uid=*"
# Filter = "(uid=*)(uid=*)"
# Вернёт всех пользователей!
Защита — экранирование LDAP:
from ldap.filter import escape_filter_chars
username = request.form.get("username")
escaped = escape_filter_chars(username)
ldap_filter = f"(uid={escaped})"
results = ldap_conn.search(ldap_filter)
6. Template Injection
Уязвимый код:
# Jinja2 injection
user_input = request.args.get("name")
template = f"Hello {user_input}!"
result = jinja_env.from_string(template).render()
# Если user_input = "{{ 7*7 }}"
# Вернёт "Hello 49!"
# Если user_input = "{{ __import__(os).system(ls) }}"
# Выполнит команду!
Защита:
# ПРАВИЛЬНО - используй render() с переменными
result = jinja_env.get_template("template.html").render(name=user_input)
# В шаблоне:
# <h1>Hello {{ name }}!</h1>
# Переменные будут экранированы автоматически
Общие принципы защиты
1. Input Validation (Валидация входных данных)
from pydantic import BaseModel, validator
class UserInput(BaseModel):
email: str
age: int
@validator("email")
def email_valid(cls, v):
if "@" not in v:
raise ValueError("Invalid email")
return v
@validator("age")
def age_valid(cls, v):
if v < 0 or v > 150:
raise ValueError("Invalid age")
return v
user = UserInput(email=request.json["email"], age=request.json["age"])
2. Output Encoding (Экранирование вывода)
from markupsafe import escape
# Для HTML
html = f"<p>{escape(user_input)}</p>"
# Для JSON
import json
json_str = json.dumps({"message": user_input}) # Автоматически экранирует
# Для SQL (используй параметризованные запросы)
db.execute("SELECT * FROM users WHERE name = ?", (user_input,))
3. Parametrized Queries (Параметризованные запросы)
# ВСЕГДА используй параметры, никогда не конкатенируй
# SQLite
db.execute("SELECT * FROM users WHERE id = ?", (user_id,))
# MySQL
db.execute("SELECT * FROM users WHERE id = %s", (user_id,))
# PostgreSQL
db.execute("SELECT * FROM users WHERE id = %s", (user_id,))
# SQLAlchemy
from sqlalchemy import text
db.execute(text("SELECT * FROM users WHERE id = :id"), {"id": user_id})
4. Use Security Libraries
# bleach для очистки HTML
import bleach
clean_html = bleach.clean(user_input, tags=["p", "br"])
# python-html2text для очистки от HTML
from html import escape
# cryptography для защиты sensitive данных
from cryptography.fernet import Fernet
cipher = Fernet(key)
encrypted = cipher.encrypt(sensitive_data)
5. Least Privilege (Минимум привилегий)
# Используй отдельного пользователя БД для web приложения
# с минимальными правами (только SELECT/INSERT/UPDATE)
# НЕ используй root или администратора
# SQL:
CREATE USER app_user@localhost IDENTIFIED BY password;
GRANT SELECT, INSERT, UPDATE ON database.* TO app_user@localhost;
# Не даём права на DROP, ALTER, CREATE
6. Web Application Firewall (WAF)
У cloudflare или других провайдеров WAF
фильтрует инъекции автоматически
Чеклист безопасности
- ✓ Параметризованные запросы для БД
- ✓ Экранирование для HTML/JavaScript
- ✓ Валидация входных данных (type, length, format)
- ✓ Используй ORM вместо raw SQL
- ✓ Не используй shell=True в subprocess
- ✓ Защита от XSS (Content-Security-Policy)
- ✓ CSRF tokens для POST/PUT/DELETE
- ✓ HTTPS только
- ✓ Регулярное обновление зависимостей
- ✓ Логирование и мониторинг
Вывод: главное правило — НИКОГДА не доверяй пользовательским данным. Всегда валидируй и экранируй.