2.6 KiB
2.6 KiB
Безопасность
Базовые требования
.env— всегда в.gitignore. Никогда не коммитить.- JWT: алгоритм HS256, access_token = 60 минут, refresh_token = 30 дней
- Пароли: bcrypt через passlib
- Pydantic валидация на всех входах
- RBAC: роли user, admin
Аутентификация
JWT
# app/core/security.py
def create_access_token(data: dict, expires_delta: timedelta | None = None) -> str:
to_encode = data.copy()
expire = datetime.now(timezone.utc) + (expires_delta or timedelta(minutes=60))
to_encode.update({"exp": expire, "type": "access"})
return jwt.encode(to_encode, settings.jwt_secret_key, algorithm=settings.jwt_algorithm)
def decode_token(token: str) -> dict[str, Any] | None:
try:
return jwt.decode(token, settings.jwt_secret_key, algorithms=[settings.jwt_algorithm])
except JWTError:
return None
Password hashing
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def hash_password(password: str) -> str:
return pwd_context.hash(password)
def verify_password(plain: str, hashed: str) -> bool:
return pwd_context.verify(plain, hashed)
RBAC
| Роль | Права |
|---|---|
| user | Базовые: CRUD своих данных, запуск анализа |
| admin (is_superuser) | Управление пользователями, просмотр логов, системные настройки |
Проверка прав:
async def require_admin(user: Annotated[User, Depends(get_current_user)]) -> User:
if not user.is_superuser:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Admin access required")
return user
Sensitive Data
Никогда не логировать:
- Пароли (даже хэш)
- JWT токены
- API keys и секреты
- Email в открытом виде (только user_id)
Маскировать в логах:
- Email: u***@mail.ru
- IP: 195.208..
[ASK] Вопросы по безопасности
- Нужен ли audit log? (рекомендуется для production)
- Нужно ли шифрование данных в покое? (да, если хранятся персональные данные)
- Нужен ли rate limiting? (да, для production)
- Нужен ли CORS? (да, если фронтенд на другом домене)
- Нужен ли CSRF? (нет, если используем JWT в Bearer header)