',\n r'javascript:',\n r'on\\w+\\s*='\n ]\n sanitized = content\n for pattern in dangerous_patterns:\n sanitized = re.sub(pattern, '', sanitized, flags=re.IGNORECASE)\n return sanitized\n \n @staticmethod\n def validate_sql_injection(query: str) -> bool:\n # Использовать параметризованные запросы вместо конкатенации\n if \"'\" in query or '\"' in query:\n # Warning: может быть false positive\n pass\n return True\n\n# Всегда используй параметризованные запросы\nfrom sqlalchemy import text\n\nasync def get_user(session: AsyncSession, user_id: int):\n # ✅ Правильно: параметризованный запрос\n result = await session.execute(\n text('SELECT * FROM users WHERE id = :id'),\n {'id': user_id}\n )\n return result.scalar_one_or_none()\n```\n\n## Иерархия валидации\n\n1. **Frontend** — быстрая обратная связь (не обязательна)\n2. **API (Pydantic)** — валидация типов и формата\n3. **Service слой** — бизнес-логика валидация\n4. **Database** — constrain и уникальность\n5. **Security** — аутентификация, авторизация, санитизация\n\nВалидация на каждом уровне должна быть **независимой** — не полагайся на валидацию на предыдущем уровне.","dateCreated":"2026-03-22T20:56:39.058126","upvoteCount":0,"author":{"@type":"Person","name":"claude-haiku-4.5"}}}}
← Назад к вопросам

Какие знаешь уровни валидации?

1.0 Junior🔥 231 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Уровни валидации

Валидация — проверка корректности данных на разных уровнях приложения. Это критично для безопасности и надёжности.

1. Клиентская валидация (Frontend)

Первый уровень — немедленная обратная связь пользователю.

# Пример с использованием JavaScript (но показываю принцип)
# На фронте валидируем перед отправкой
if not email.includes('@'):
    show_error('Invalid email')
else:
    send_to_backend()

Преимущества: быстрая обратная связь, экономия трафика.

Недостатки: клиент может быть скомпрометирован, легко обойти.

2. API валидация (Server-Side)

Проверка входных данных на сервере — обязательна, так как клиент ненадёжен.

2.1 Валидация типов

from fastapi import FastAPI
from pydantic import BaseModel, Field, EmailStr

app = FastAPI()

class UserCreate(BaseModel):
    name: str = Field(..., min_length=1, max_length=100)
    email: EmailStr
    age: int = Field(..., ge=18, le=150)
    phone: str | None = None

@app.post('/users')
async def create_user(user: UserCreate):
    # Pydantic автоматически валидирует типы
    return {'user': user}

Pydantic проверяет:

  • Тип данных (str, int, email и т.д.)
  • Диапазоны (ge, le, min_length, max_length)
  • Формат (EmailStr, HttpUrl, UUID)
  • Кастомные правила

2.2 Бизнес-логика валидация

from pydantic import BaseModel, validator, root_validator

class UserCreate(BaseModel):
    username: str
    password: str
    password_confirm: str
    
    @validator('password')
    def validate_password(cls, v):
        if len(v) < 8:
            raise ValueError('Password must be 8+ characters')
        if not any(c.isupper() for c in v):
            raise ValueError('Password must contain uppercase')
        return v
    
    @root_validator()
    def validate_passwords_match(cls, values):
        if values.get('password') != values.get('password_confirm'):
            raise ValueError('Passwords do not match')
        return values

# Использование
try:
    user = UserCreate(
        username='john',
        password='SecurePass123',
        password_confirm='SecurePass123'
    )
except ValueError as e:
    print(f'Validation error: {e}')

3. Валидация БД (Database)

Констрейнты на уровне БД — последняя защита от некорректных данных.

from sqlalchemy import Column, String, Integer, CheckConstraint, UniqueConstraint
from sqlalchemy.orm import declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    
    id = Column(Integer, primary_key=True)
    email = Column(String(255), unique=True, nullable=False)
    username = Column(String(100), nullable=False)
    age = Column(
        Integer,
        CheckConstraint('age >= 18 AND age <= 150'),
        nullable=False
    )
    
    __table_args__ = (
        UniqueConstraint('username', name='uq_username'),
    )

Соответствующая миграция (Goose):

-- migrations/0001_create_users.sql
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) UNIQUE NOT NULL,
    username VARCHAR(100) NOT NULL,
    age INTEGER CHECK (age >= 18 AND age <= 150) NOT NULL,
    CONSTRAINT uq_username UNIQUE (username)
);

4. Валидация бизнес-правил

Проверка логики, которая требует доступа к БД.

from sqlalchemy.ext.asyncio import AsyncSession

class UserService:
    @staticmethod
    async def create_user(
        session: AsyncSession,
        data: UserCreate
    ) -> User:
        # Проверить уникальность email
        existing = await session.execute(
            select(User).where(User.email == data.email)
        )
        if existing.scalar_one_or_none():
            raise ValueError('Email already registered')
        
        # Проверить бизнес-правила
        if data.age < 18:
            raise ValueError('Must be 18+')
        
        # Создать пользователя
        user = User(
            email=data.email,
            username=data.username,
            age=data.age
        )
        session.add(user)
        await session.commit()
        return user

5. Валидация аутентификации и авторизации

from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPCredentials

class SecurityService:
    @staticmethod
    async def verify_token(credentials: HTTPCredentials) -> dict:
        try:
            payload = jwt.decode(
                credentials.credentials,
                SECRET_KEY,
                algorithms=['HS256']
            )
            user_id: str = payload.get('sub')
            if user_id is None:
                raise HTTPException(
                    status_code=status.HTTP_401_UNAUTHORIZED,
                    detail='Invalid token'
                )
            return {'user_id': user_id}
        except jwt.InvalidTokenError:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail='Invalid token'
            )

security = HTTPBearer()

@app.post('/protected')
async def protected_route(auth=Depends(security)):
    user_data = await SecurityService.verify_token(auth)
    return user_data

6. Валидация безопасности

import re
from typing import Annotated

class SanitizationService:
    @staticmethod
    def sanitize_html(content: str) -> str:
        # Удалить потенциально опасные теги
        dangerous_patterns = [
            r'<script[^>]*>.*?</script>',
            r'javascript:',
            r'on\w+\s*='
        ]
        sanitized = content
        for pattern in dangerous_patterns:
            sanitized = re.sub(pattern, '', sanitized, flags=re.IGNORECASE)
        return sanitized
    
    @staticmethod
    def validate_sql_injection(query: str) -> bool:
        # Использовать параметризованные запросы вместо конкатенации
        if "'" in query or '"' in query:
            # Warning: может быть false positive
            pass
        return True

# Всегда используй параметризованные запросы
from sqlalchemy import text

async def get_user(session: AsyncSession, user_id: int):
    # ✅ Правильно: параметризованный запрос
    result = await session.execute(
        text('SELECT * FROM users WHERE id = :id'),
        {'id': user_id}
    )
    return result.scalar_one_or_none()

Иерархия валидации

  1. Frontend — быстрая обратная связь (не обязательна)
  2. API (Pydantic) — валидация типов и формата
  3. Service слой — бизнес-логика валидация
  4. Database — constrain и уникальность
  5. Security — аутентификация, авторизация, санитизация

Валидация на каждом уровне должна быть независимой — не полагайся на валидацию на предыдущем уровне.