Безопасность JavaScript приложений: топ-10 уязвимостей

Онлайн-тренажер Python для начинающих

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

Начать курс

Безопасность JavaScript приложений: топ-10 уязвимостей

Современные JavaScript-приложения на Node.js обрабатывают огромные объемы чувствительных данных, что делает их привлекательной целью для злоумышленников. По данным OWASP, большинство взломов происходит из-за типовых ошибок, которые можно предотвратить. В этой статье мы разберем 10 самых распространенных уязвимостей, приведем реальные примеры кода и покажем, как защитить ваше приложение.

1. XSS (Cross-Site Scripting)

Межсайтовый скриптинг — одна из старейших, но до сих пор актуальных угроз. Злоумышленник внедряет вредоносный скрипт в веб-страницу, который выполняется в браузере жертвы.

// Уязвимый код
app.get('/search', (req, res) => {
    const query = req.query.q;
    res.send(`<h2>Результаты поиска для: ${query}</h2>`);
});

// Безопасная версия
const escapeHtml = (str) => {
    return str.replace(/&/g, '&amp;')
              .replace(/</g, '&lt;')
              .replace(/>/g, '&gt;')
              .replace(/"/g, '&quot;')
              .replace(/'/g, '&#039;');
};

app.get('/search', (req, res) => {
    const query = escapeHtml(req.query.q || '');
    res.send(`<h2>Результаты поиска для: ${query}</h2>`);
});

2. SQL Injection

Внедрение SQL-кода происходит, когда пользовательский ввод напрямую конкатенируется в SQL-запрос. Это может привести к утечке или удалению данных.

// Уязвимый код
const userId = req.body.id;
const query = `SELECT * FROM users WHERE id = ${userId}`;

// Безопасная версия с параметризованными запросами
const userId = req.body.id;
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [userId], (err, results) => {
    // обработка результатов
});

3. Небезопасная десериализация

Node.js часто использует JSON.parse(), но если вы работаете с другими форматами (например, Buffer), злоумышленник может внедрить вредоносные данные.

// Опасный подход
const data = JSON.parse(req.body.data); // может содержать __proto__

// Безопасный подход
const safeParse = (json) => {
    const data = JSON.parse(json);
    // Рекурсивно удаляем опасные свойства
    return JSON.parse(JSON.stringify(data));
};

4. CSRF (Cross-Site Request Forgery)

Атака, при которой злоумышленник заставляет пользователя выполнить нежелательное действие на сайте, где тот авторизован.

// Установка защиты с помощью csurf
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });

app.post('/transfer', csrfProtection, (req, res) => {
    // безопасная обработка перевода
});

5. Небезопасная аутентификация

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

// Правильное хэширование паролей
const bcrypt = require('bcrypt');

async function createUser(password) {
    const salt = await bcrypt.genSalt(12);
    const hash = await bcrypt.hash(password, salt);
    // сохраняем hash в БД
}

async function checkPassword(plainPassword, hash) {
    return await bcrypt.compare(plainPassword, hash);
}

6. Утечка конфиденциальных данных

Отправка стека ошибок клиенту или логирование паролей — частая ошибка разработчиков.

// Неправильно
app.use((err, req, res, next) => {
    res.status(500).json({ error: err.stack });
});

// Правильно
app.use((err, req, res, next) => {
    console.error(err); // логируем на сервере
    res.status(500).json({ error: 'Внутренняя ошибка сервера' });
});

7. Небезопасная конфигурация

Использование стандартных портов, включенный режим отладки в продакшене и слабые CORS-политики.

// Безопасная конфигурация CORS
const cors = require('cors');
const corsOptions = {
    origin: 'https://myapp.com',
    methods: ['GET', 'POST'],
    allowedHeaders: ['Content-Type', 'Authorization']
};
app.use(cors(corsOptions));

// Отключаем заголовок X-Powered-By
app.disable('x-powered-by');

8. Prototype Pollution

Уязвимость, характерная для JavaScript, когда злоумышленник может изменить прототип объекта.

// Опасный merge
function merge(target, source) {
    for (let key in source) {
        if (typeof source[key] === 'object') {
            target[key] = merge(target[key] || {}, source[key]);
        } else {
            target[key] = source[key];
        }
    }
    return target;
}

// Безопасная версия
function safeMerge(target, source) {
    const result = { ...target };
    for (let key in source) {
        if (key === '__proto__' || key === 'constructor') continue;
        if (typeof source[key] === 'object' && source[key] !== null) {
            result[key] = safeMerge(result[key] || {}, source[key]);
        } else {
            result[key] = source[key];
        }
    }
    return result;
}

9. Небезопасные зависимости

Использование устаревших пакетов с известными уязвимостями.

// Регулярная проверка зависимостей
// Установите npm audit
// В package.json добавьте:
{
    "scripts": {
        "audit": "npm audit",
        "outdated": "npm outdated"
    }
}

// Используйте Snyk для автоматического мониторинга
// npm install -g snyk
// snyk test

10. Отсутствие rate limiting

Без ограничения количества запросов злоумышленник может осуществить DDoS-атаку или перебор паролей.

// Установка rate limiting с express-rate-limit
const rateLimit = require('express-rate-limit');

const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 минут
    max: 100, // максимум 100 запросов
    message: 'Слишком много запросов, попробуйте позже'
});

app.use('/api/', limiter);

// Для авторизации - более                

Блоги

Рекомендаций по книгам