OWASP Top 10

OWASP Top 10 — список 10 самых критичных уязвимостей веб-приложений, обновляемый каждые 3-4 года. Стандарт де-факто для веб-безопасности.

Зачем нужно

OWASP Top 10 — это минимум, который должен знать каждый разработчик. Не нужно быть экспертом по безопасности, но нужно понимать главные угрозы и уметь от них защищаться. Многие компании требуют соответствие OWASP Top 10 при аудите.

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

Аудит безопасности, code review, проектирование архитектуры, требования к безопасности в ТЗ, сертификация (PCI DSS ссылается на OWASP).

Предпосылки

XSS, CSRF, SQL Injection, HTTPS и SSL

OWASP Top 10 (2021)

A01: Broken Access Control

Нарушение контроля доступа — пользователь может получить доступ к чужим ресурсам.

// УЯЗВИМО: нет проверки прав
app.get('/api/users/:id', async (req, res) => {
  const user = await db.getUser(req.params.id);
  res.json(user); // Любой может запросить любого пользователя!
});

// БЕЗОПАСНО: проверка прав
app.get('/api/users/:id', auth, async (req, res) => {
  if (req.user.id !== req.params.id && req.user.role !== 'admin') {
    return res.status(403).json({ error: 'Доступ запрещён' });
  }
  const user = await db.getUser(req.params.id);
  res.json(user);
});

Защита: проверка прав на каждый запрос, deny by default, RBAC (ролевая модель).

A02: Cryptographic Failures

Криптографические ошибки — незащищённые данные: пароли в plaintext, HTTP вместо HTTPS, слабые алгоритмы.

// ПЛОХО:
const hash = md5(password);        // MD5 — не для паролей
const token = base64(userId);       // Base64 — не шифрование

// ХОРОШО:
const hash = await bcrypt.hash(password, 12);
const token = jwt.sign({ userId }, SECRET, { expiresIn: '1h' });

Защита: HTTPS everywhere, bcrypt/argon2 для паролей, AES-256 для данных, не изобретать криптографию.

A03: Injection

Инъекции — SQL, NoSQL, OS Command, LDAP injection.

// УЯЗВИМО:
const q = `SELECT * FROM users WHERE name = '${name}'`;

// БЕЗОПАСНО:
const q = 'SELECT * FROM users WHERE name = $1';
await db.query(q, [name]);

Защита: параметризованные запросы, ORM, валидация ввода, WAF.

A04: Insecure Design

Небезопасный дизайн — архитектурные ошибки, которые нельзя исправить патчем.

Пример: система восстановления пароля задаёт вопрос
"Кличка вашего питомца?" — ответ легко найти в соцсетях.

Пример: нет rate limiting на API авторизации — brute force.

Защита: threat modeling на этапе проектирования, secure design patterns, abuse stories.

A05: Security Misconfiguration

Неправильная конфигурация — стандартные пароли, открытые debug-режимы, лишние сервисы.

// ПЛОХО:
app.use(express.errorHandler); // Stack trace в production!
// Ответ: "Error: ENOENT at /app/src/controllers/user.js:42"

// ХОРОШО:
app.use((err, req, res, next) => {
  console.error(err); // Логируем для себя
  res.status(500).json({ error: 'Внутренняя ошибка' }); // Без деталей
});

Защита: убрать дефолтные учётки, отключить debug в prod, минимум прав, security headers (Helmet).

A06: Vulnerable and Outdated Components

Уязвимые зависимости — библиотеки с известными уязвимостями.

# Проверка уязвимостей
npm audit
npm audit fix

# Snyk — более глубокий анализ
npx snyk test

Защита: регулярные npm audit, Dependabot/Renovate, мониторинг CVE.

A07: Identification and Authentication Failures

Ошибки аутентификации — слабые пароли, brute force, утечка сессий.

// Защита от brute force
const rateLimit = require('express-rate-limit');
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 минут
  max: 5,                    // Максимум 5 попыток
  message: 'Слишком много попыток. Попробуйте через 15 минут.',
});
app.post('/login', loginLimiter, loginHandler);

Защита: rate limiting, MFA, безопасное хранение паролей, защита сессий.

A08: Software and Data Integrity Failures

Нарушение целостности — незащищённый CI/CD, непроверенные обновления, десериализация без проверки.

<!-- Subresource Integrity — проверка хеша CDN-скриптов -->
<script
  src="https://cdn.example.com/lib.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8w"
  crossorigin="anonymous">
</script>

Защита: SRI для CDN, подпись пакетов, защита CI/CD-пайплайна.

A09: Security Logging and Monitoring Failures

Недостаточное логирование — атаки происходят, но никто не замечает.

// Логируем важные события безопасности
const winston = require('winston');

app.post('/login', (req, res) => {
  if (!authenticated) {
    logger.warn('Failed login attempt', {
      ip: req.ip,
      email: req.body.email,
      timestamp: new Date,
      userAgent: req.headers['user-agent'],
    });
  }
});

Защита: логирование входов/ошибок, мониторинг аномалий, оповещения, SIEM.

A10: Server-Side Request Forgery (SSRF)

SSRF — приложение отправляет запрос по URL, указанному пользователем, позволяя обращаться к внутренним ресурсам.

// УЯЗВИМО:
app.get('/fetch', async (req, res) => {
  const response = await fetch(req.query.url); // Пользователь контролирует URL!
  res.json(await response.json());
});
// Атака: /fetch?url=http://169.254.169.254/latest/meta-data/ (AWS metadata)

// БЕЗОПАСНО: whitelist + валидация
const allowedDomains = ['api.example.com', 'data.example.com'];

app.get('/fetch', async (req, res) => {
  const url = new URL(req.query.url);
  if (!allowedDomains.includes(url.hostname)) {
    return res.status(403).json({ error: 'Домен не разрешён' });
  }
  const response = await fetch(url);
  res.json(await response.json());
});

Защита: whitelist URL/доменов, блокировка приватных IP, сетевая сегментация.

Чек-лист для разработчика

# Уязвимость Быстрая проверка
A01 Access Control Проверяю права на каждом endpoint?
A02 Crypto HTTPS? bcrypt для паролей?
A03 Injection Параметризованные запросы?
A04 Insecure Design Есть ли threat model?
A05 Misconfiguration Debug выключен? Headers настроены?
A06 Components npm audit чисто?
A07 Auth Rate limiting? MFA?
A08 Integrity SRI? Защита CI/CD?
A09 Logging Логирую неудачные входы?
A10 SSRF Валидирую внешние URL?

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

1. «Безопасность — забота отдела security»

Каждый разработчик отвечает за безопасность своего кода.

2. Security through obscurity

ПЛОХО: "Никто не догадается вызвать /admin/delete-all"
ХОРОШО: Проверка прав + аутентификация на каждом endpoint

3. Только frontend-валидация

// Клиент можно обойти через DevTools, curl, Postman
// ВСЕГДА валидируй на сервере

Практика

  1. Проведи npm audit в своём проекте и исправь найденные уязвимости
  2. Добавь rate limiting для endpoint авторизации
  3. Проверь, есть ли проверка прав на всех API-endpoint
  4. Настрой логирование неудачных попыток входа
  5. Используй OWASP ZAP для автоматического сканирования своего приложения

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

Ресурсы