Принцип наименьших привилегий

Принцип наименьших привилегий (Least Privilege / PoLP) — каждый компонент системы (пользователь, процесс, сервис) должен иметь только те права, которые минимально необходимы для выполнения его функций, и не более того.

Зачем нужно

Если скомпрометирован компонент с избыточными правами, атака распространяется на всю систему. Ограничение прав минимизирует радиус поражения: взломанный read-only пользователь БД не позволит удалить данные; сервис без доступа к S3 не сольёт файлы.

Где используется

  • Права пользователей в приложении (роли: admin / editor / viewer)
  • БД-пользователи: отдельные учётные записи для каждого сервиса
  • IAM-политики в AWS/GCP/Azure
  • Docker-контейнеры: запуск без root
  • SSH-доступ и серверные пользователи

Основной контент

Роли в приложении (RBAC)

// Ролевая модель вместо флага isAdmin
const PERMISSIONS = {
  admin:  ['read', 'write', 'delete', 'manage_users'],
  editor: ['read', 'write'],
  viewer: ['read'],
};

function hasPermission(userRole, action) {
  return PERMISSIONS[userRole]?.includes(action) ?? false;
}

// Middleware
function requirePermission(action) {
  return (req, res, next) => {
    if (!hasPermission(req.user.role, action)) {
      return res.status(403).json({ error: 'Insufficient permissions' });
    }
    next;
  };
}

app.delete('/api/posts/:id', authenticate, requirePermission('delete'), deletePost);

БД: минимальные права для каждого сервиса

-- Отдельный пользователь для каждого сервиса
CREATE USER api_service WITH PASSWORD 'strong_password';
GRANT SELECT, INSERT, UPDATE ON orders, users TO api_service;
-- НЕТ прав на DELETE, DROP, TRUNCATE

CREATE USER reports_service WITH PASSWORD 'another_password';
GRANT SELECT ON ALL TABLES IN SCHEMA public TO reports_service;
-- Только чтение

AWS IAM: минимальные политики

{
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "s3:GetObject",
      "s3:PutObject"
    ],
    "Resource": "arn:aws:s3:::my-uploads-bucket/*"
    // Только конкретный бакет, только Get/Put — не Delete, не ListBuckets
  }]
}

Docker: без root

FROM node:20-alpine

# Создаём непривилегированного пользователя
RUN addgroup -g 1001 appgroup && adduser -u 1001 -G appgroup -s /bin/sh -D appuser

WORKDIR /app
COPY --chown=appuser:appgroup . .
RUN npm ci --only=production

USER appuser  # Запуск от непривилегированного пользователя
EXPOSE 3000
CMD ["node", "server.js"]

Node.js: минимальные права процесса

# Запуск на порту 80 без root через capabilities
setcap 'cap_net_bind_service=+ep' /usr/local/bin/node

# Или через nginx reverse proxy (рекомендуется):
# Node на порту 3000 (без root), nginx на 80/443 с proxy_pass

Частые ошибки

  • Один суперпользователь БД для всего приложения — взлом одного сервиса даёт полный доступ
  • Запуск Docker-контейнеров от root — docker run --privileged катастрофически опасен
  • IAM-политики с "Action": "*", "Resource": "*" — даёт полный доступ к облаку
  • "Временные" расширенные права, которые никто не убирает

Связанные темы

Ресурсы