← Назад к вопросам
Всегда ли нужно валидировать только POST запрос
2.0 Middle🔥 121 комментариев
#REST API и HTTP#Безопасность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Валидация запросов: нужна ли она для всех HTTP методов?
Короткий ответ: ДА, валидация нужна для ВСЕХ запросов, не только для POST. Это распространённое заблуждение, которое приводит к уязвимостям.
1. Почему только POST — неправильно?
Проблема
Есть мнение что валидация нужна только для:
- POST (создание данных)
- PUT/PATCH (обновление данных)
А для GET/DELETE якобы не нужна.
Реальность
Все методы принимают пользовательский ввод, и всё это нужно валидировать!
2. GET запросы тоже нужно валидировать
Пример: Уязвимость в GET
from fastapi import FastAPI, Query
app = FastAPI()
# НЕПРАВИЛЬНО: Валидация отсутствует
@app.get("/users")
def get_users(user_id: int = Query(...)): # Может быть любое число
# user_id = -1
# user_id = 999999
# user_id = 0
# user_id = None
user = db.query(User).filter(User.id == user_id).first()
return user
# Проблемы:
# - SQL injection (если неправильно сделан запрос)
# - Утечка информации (можно перебрать все ID)
# - DoS (очень большой ID может вызвать проблемы)
# ПРАВИЛЬНО: С валидацией
@app.get("/users")
def get_users(user_id: int = Query(..., gt=0, le=1000000)):
# Гарантирует: 0 < user_id <= 1000000
user = db.query(User).filter(User.id == user_id).first()
if not user:
return {"error": "Not found"}
return user
Пример: Query параметры
from fastapi import FastAPI, Query
from pydantic import validator
app = FastAPI()
# НЕПРАВИЛЬНО: Нет валидации
@app.get("/search")
def search(query: str = Query(...)):
# query может быть:
# - пустой строкой
# - очень длинной (DoS)
# - содержать SQL injection
results = db.raw_query(f"SELECT * FROM users WHERE name LIKE '%{query}%'")
return results
# ПРАВИЛЬНО: С валидацией
@app.get("/search")
def search(query: str = Query(..., min_length=1, max_length=100)):
# Гарантирует: 1 <= len(query) <= 100
# Используем parameterized query!
results = db.query(User).filter(
User.name.contains(query)
).limit(50).all()
return results
3. DELETE запросы тоже нужно валидировать
Пример: DELETE уязвимость
# НЕПРАВИЛЬНО: Нет валидации
@app.delete("/users/{user_id}")
def delete_user(user_id: int):
# user_id может быть:
# - -1 (ошибка в БД, удалит что-то неправильное)
# - 0 (root admin?)
# - очень большое число (ошибка)
db.query(User).filter(User.id == user_id).delete()
return {"status": "deleted"}
# Проблемы:
# - Можно удалить любого пользователя
# - Нет проверки авторизации
# - Нет проверки существования
# ПРАВИЛЬНО: С валидацией и авторизацией
@app.delete("/users/{user_id}")
def delete_user(user_id: int, current_user: User = Depends(get_current_user)):
# Валидация: user_id валиден?
if user_id <= 0:
return {"error": "Invalid user_id"}
# Авторизация: имеет ли право удалить?
if user_id != current_user.id and not current_user.is_admin:
return {"error": "Forbidden"}
# Проверка существования
user = db.query(User).get(user_id)
if not user:
return {"error": "Not found"}
db.delete(user)
db.commit()
return {"status": "deleted"}
4. Что нужно валидировать
Для всех методов
from fastapi import FastAPI, Path, Query
from pydantic import BaseModel, validator
# 1. Path параметры
@app.get("/items/{item_id}")
def get_item(item_id: int = Path(..., gt=0)): # item_id > 0
pass
# 2. Query параметры
@app.get("/search")
def search(query: str = Query(..., min_length=1, max_length=100)):
pass
# 3. Headers
@app.get("/data")
def get_data(user_agent: str = Header(...)):
# Проверить формат user-agent
if "bot" in user_agent.lower():
return {"error": "Bots not allowed"}
pass
# 4. Body для POST/PUT
class UserCreate(BaseModel):
email: str
password: str
@validator("email")
def validate_email(cls, v):
if "@" not in v:
raise ValueError("Invalid email")
return v
@validator("password")
def validate_password(cls, v):
if len(v) < 8:
raise ValueError("Password too short")
return v
@app.post("/users")
def create_user(user: UserCreate):
# user уже валидирован благодаря Pydantic
pass
5. Типы валидации
from pydantic import BaseModel, Field, validator, EmailStr
import re
class UserCreate(BaseModel):
# 1. Type validation (встроено)
age: int # Должно быть число
# 2. Range validation
age: int = Field(..., ge=18, le=120) # 18 <= age <= 120
# 3. Length validation
password: str = Field(..., min_length=8, max_length=100)
# 4. Pattern validation (regex)
phone: str = Field(..., regex=r"^\+?1?\d{9,15}$")
# 5. Email validation
email: EmailStr
# 6. Custom validation
@validator("password")
def validate_password(cls, v):
if not any(char.isupper() for char in v):
raise ValueError("Password must contain uppercase")
return v
# 7. Cross-field validation
@validator("confirm_password")
def validate_confirm(cls, v, values):
if "password" in values and v != values["password"]:
raise ValueError("Passwords don't match")
return v
6. На уровне БД (дополнительно)
# Всегда добавляй ограничения на уровне БД
from sqlalchemy import Column, Integer, String, CheckConstraint
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
age = Column(Integer, CheckConstraint("age >= 18 and age <= 120"))
email = Column(String(255), unique=True, nullable=False)
password = Column(String(255), nullable=False)
# Проверка на уровне БД
__table_args__ = (
CheckConstraint("length(password) >= 8"),
)
7. Чеклист валидации
- Path параметры валидированы?
- Query параметры валидированы?
- Body параметры валидированы?
- Headers проверены?
- Типы данных проверены?
- Диапазоны значений проверены?
- Формат строк проверен (email, phone, UUID)?
- Авторизация проверена?
- SQL injection защита (parameterized queries)?
- Rate limiting установлен?
Резюме
Валидация нужна для ВСЕХ HTTP методов:
- GET — валидировать query параметры, path параметры
- POST — валидировать body
- PUT/PATCH — валидировать body и path параметры
- DELETE — валидировать path параметры и авторизацию
- HEAD/OPTIONS — менее критично но желательно
Правило: Никогда не доверяй пользовательскому вводу, независимо от HTTP метода.