Cookie: безопасные атрибуты (HttpOnly, Secure, SameSite)
Атрибуты куки HttpOnly, Secure и SameSite — механизмы защиты от XSS, перехвата трафика и CSRF-атак.
Зачем нужно
Кука с session ID или токеном — высокоценная цель для атакующего. Без защитных атрибутов XSS может украсть куку, незашифрованный HTTP — открыть её перехватчику, а CSRF — использовать куку для атаки от имени пользователя. Три атрибута вместе закрывают эти векторы атак.
Где используется
- Хранение session ID на клиенте
- Refresh token в куке (безопаснее, чем в localStorage)
- Любые куки с чувствительными данными
- Express.js, Django, Rails — при настройке cookies
HttpOnly
HttpOnly — кука недоступна через JavaScript (document.cookie)
Защищает от: XSS — скрипт не может прочитать куку
# Сервер устанавливает куку
Set-Cookie: sessionId=abc123; HttpOnly
# JavaScript НЕ МОЖЕТ прочитать
console.log(document.cookie); // "" — пусто
// Express
res.cookie('sessionId', sessionId, { httpOnly: true });
Secure
Secure — кука передаётся только по HTTPS
Защищает от: перехвата трафика (man-in-the-middle)
Set-Cookie: sessionId=abc123; Secure
# При HTTP-запросе браузер НЕ отправит эту куку
// Express — production
res.cookie('sessionId', sessionId, {
secure: process.env.NODE_ENV === 'production', // только HTTPS в prod
});
SameSite
SameSite контролирует, когда кука отправляется при кросс-сайт запросах
Защищает от: CSRF — атака с другого сайта
Значения SameSite
SameSite=Strict — кука только при навигации с того же сайта
Пример: кнопка «Оплатить» с другого сайта не получит куку
Минус: ссылки из email тоже не получат куку (неудобно)
SameSite=Lax (рекомендуется) — кука при безопасных кросс-сайт навигациях (GET, ссылка)
Пример: ссылка из email → кука отправлена (пользователь видит свой профиль)
CSRF-запрос с POST → кука НЕ отправлена
Это дефолт в современных браузерах
SameSite=None — всегда отправлять куку (нужно с Secure)
Использование: сторонние куки в iframe, CORS с credentials
# Оптимальная комбинация для session cookie
Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=604800
Настройка в Express
const session = require('express-session');
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 дней в мс
path: '/',
},
}));
Ручная установка куки
// Установка
res.setHeader('Set-Cookie', [
`token=${token}; HttpOnly; Secure; SameSite=Lax; Max-Age=86400; Path=/`,
]);
// Через res.cookie в Express
res.cookie('token', token, {
httpOnly: true,
secure: true,
sameSite: 'lax',
maxAge: 86400 * 1000,
});
// Очистка (logout)
res.clearCookie('token', { httpOnly: true, secure: true, path: '/' });
Частые ошибки
- Хранение JWT в
localStorageвместо HttpOnly-куки — доступно для XSS Secureбез HTTPS — кука никогда не передаётся (dev окружение)SameSite=NoneбезSecure— браузеры игнорируют такую куку- Не указывают
Path=/— кука отправляется только с текущего пути
Связанные темы
- _MOC Безопасность
- _MOC Сеть
- Cookie -- как работают
- Sessions и Cookies в Express
- Сессии -- серверная авторизация
- JWT