Sessions и Cookies в Express
Практическое руководство по настройке session middleware и работе с куками в приложениях на Express.js.
Зачем нужно
Express не имеет встроенной поддержки сессий — она добавляется через express-session. Без понимания настройки хранилища, опций куки и жизненного цикла сессии легко создать небезопасное или нерабочее приложение (например, потеря сессий при перезапуске или утечка через незащищённые куки).
Где используется
- Веб-приложения с серверной аутентификацией
- Admin-панели с управлением сессиями
- MVP и учебные проекты перед внедрением JWT
- Интеграция с Passport.js (OAuth, Local Strategy)
Минимальная установка
npm install express express-session cookie-parser connect-redis redis
Базовая настройка
const express = require('express');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const RedisStore = require('connect-redis').default;
const { createClient } = require('redis');
const app = express;
app.use(express.json());
app.use(cookieParser(process.env.COOKIE_SECRET));
// Настройка Redis хранилища
const redisClient = createClient({ url: process.env.REDIS_URL });
redisClient.connect.catch(console.error);
// Настройка сессий
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET, // минимум 32 символа
resave: false, // не перезаписывать неизменённые сессии
saveUninitialized: false, // не создавать сессии для анонимов
name: 'sid', // имя куки (скрываем 'connect.sid')
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 2 * 60 * 60 * 1000, // 2 часа
path: '/',
},
}));
Аутентификация
const bcrypt = require('bcrypt');
// Логин
app.post('/auth/login', async (req, res) => {
const { email, password } = req.body;
const user = await db.users.findByEmail(email);
if (!user || !await bcrypt.compare(password, user.passwordHash)) {
return res.status(401).json({ error: 'Неверные данные' });
}
// Регенерация session ID — защита от session fixation
req.session.regenerate((err) => {
if (err) return res.status(500).end();
req.session.userId = user.id;
req.session.role = user.role;
req.session.loginAt = Date.now();
res.json({ ok: true, user: { id: user.id, name: user.name } });
});
});
// Middleware — проверка аутентификации
function requireAuth(req, res, next) {
if (!req.session?.userId) {
return res.status(401).json({ error: 'Требуется авторизация' });
}
next;
}
// Middleware — проверка роли
function requireRole(role) {
return (req, res, next) => {
if (req.session.role !== role) {
return res.status(403).json({ error: 'Доступ запрещён' });
}
next;
};
}
// Защищённые маршруты
app.get('/api/me', requireAuth, async (req, res) => {
const user = await db.users.find(req.session.userId);
res.json({ id: user.id, name: user.name, email: user.email });
});
app.get('/api/admin/users', requireAuth, requireRole('admin'), async (req, res) => {
const users = await db.users.findAll;
res.json(users);
});
// Logout
app.post('/auth/logout', (req, res) => {
req.session.destroy(err => {
res.clearCookie('sid', { path: '/' });
res.json({ ok: true });
});
});
Работа с куками напрямую
// Установка куки
app.get('/set-prefs', (req, res) => {
// Простая кука (без подписи)
res.cookie('lang', 'ru', {
maxAge: 365 * 24 * 60 * 60 * 1000,
sameSite: 'lax',
path: '/',
});
// Подписанная кука (защита от подделки, требует cookieParser с secret)
res.cookie('userId', '42', {
signed: true,
httpOnly: true,
secure: true,
sameSite: 'lax',
});
res.json({ ok: true });
});
// Чтение куки
app.get('/prefs', (req, res) => {
const lang = req.cookies.lang; // обычная
const userId = req.signedCookies.userId; // подписанная (false если подделана)
res.json({ lang, userId });
});
Частые ошибки
MemoryStoreв продакшне — сессии теряются при рестарте- Слишком слабый
secret(менее 32 символов) — уязвимость подписи resave: trueбез необходимости — лишняя запись в Redis на каждый запрос- Не вызывают
regenerateпосле логина — session fixation saveUninitialized: true— лишние пустые сессии для анонимных пользователей
Связанные темы
- _MOC Сеть
- Cookie -- как работают
- Cookie -- безопасные атрибуты (HttpOnly, Secure, SameSite)
- Session Management -- лучшие практики
- Сессии -- серверная авторизация