Сессии, куки и flash-сообщения
HTTP не помнит пользователя между запросами. Сессии и куки добавляют «память»: сервер узнаёт вернувшегося пользователя и хранит для него данные.
Каждый HTTP-запрос независим — сервер по умолчанию не знает, кто к нему пришёл. Кука — маленький файл у клиента, который браузер шлёт с каждым запросом. session во Flask — словарь, который сохраняется в подписанной куке, поэтому пользователь не может его подделать.
HTTP без состояния (stateless): два запроса от одного человека для сервера — два незнакомца. Чтобы «узнавать» пользователя (вошёл в систему, корзина покупок), нужна память. Её дают куки — пары ключ-значение, которые сервер просит браузер хранить и присылать обратно.
Flask поверх кук даёт удобный объект session — он выглядит как словарь, но автоматически сохраняется в подписанной куке на стороне клиента:
from flask import session
@app.route("/login", methods=["POST"])
def login():
session["user_id"] = 42 # сохранится в куке
return redirect(url_for("profile"))
@app.route("/logout")
def logout():
session.pop("user_id", None) # очистить
return redirect(url_for("index"))
Важно: session подписана SECRET_KEY, но не зашифрована — клиент видит её содержимое, но не может подменить (подпись не сойдётся). Поэтому в session нельзя класть секреты, только идентификаторы.
Flash-сообщения — частный случай: одноразовое сообщение, которое показывается на следующей странице (например «Вы вошли»). flash кладёт его в session, get_flashed_messages забирает — и оно исчезает.
from flask import flash
flash("Профиль сохранён", "success")
# в шаблоне: {% for msg in get_flashed_messages() %}...{% endfor %}
Понимание, что session по умолчанию хранится у клиента в подписанной куке, снимает множество вопросов и предостерегает от ошибок. Подпись гарантирует целостность — клиент не подменит значения, — но не конфиденциальность: содержимое куки читаемо, поэтому секреты туда не кладут, только идентификаторы. Размер куки ограничен примерно четырьмя килобайтами, так что большие данные в session не поместятся — для них хранят на сервере по id из сессии. Куки стоит сопровождать защитными флагами: HttpOnly (недоступна из JavaScript, защита от кражи через XSS), Secure (только по HTTPS), SameSite (ограничивает отправку с чужих сайтов, помогает против CSRF). Flash — частный изящный приём поверх сессии для одноразовых уведомлений.
Как работает под капотом
Сервер не хранит session у себя — он отдаёт её клиенту в подписанной куке. На следующем запросе браузер присылает куку назад, сервер проверяет подпись и восстанавливает словарь. Подпись гарантирует, что клиент не менял данные.
Запрос 1 (login)
│ session["user_id"]=42
▼ сервер подписывает: данные + подпись(SECRET_KEY)
Set-Cookie: session=<данные.подпись>
▼ браузер хранит
Запрос 2 (любой)
│ браузер шлёт куку обратно
▼ сервер проверяет подпись → восстанавливает session
подпись не сошлась? → данные отброшены (подмена)
Смоделируем подписанную сессию обычным Python.
import hashlib
SECRET = "my-secret-key"
def sign(data):
sig = hashlib.sha256((data + SECRET).encode()).hexdigest()[:12]
return data + "." + sig
def verify(cookie):
data, sig = cookie.rsplit(".", 1)
expected = hashlib.sha256((data + SECRET).encode()).hexdigest()[:12]
return data if sig == expected else None
cookie = sign("user_id=42")
print("кука:", cookie)
print("честная:", verify(cookie))
print("подделка:", verify("user_id=999." + cookie.split(".")[1]))
Запусти: честная кука восстанавливается, подделанная (изменили user_id) отвергается — подпись не сходится. Так Flask доверяет данным из session, не храня их у себя.
Частые ошибки
- Класть секреты в session. Клиент видит содержимое. Храни id, а не пароли/токены.
- Забыть get_flashed_messages в шаблоне. Тогда flash-сообщения копятся и не показываются.
- Думать, что session на сервере. По умолчанию она в куке у клиента (ограничена ~4 КБ).
Best practices
- В session — только идентификаторы; чувствительные данные держи на сервере по id.
- Ставь куки флаги Secure/HttpOnly/SameSite для защиты.
- Flash используй для одноразовых уведомлений, не для постоянных данных.
Что запомнить
- Куки дают HTTP «память» между запросами.
- session — подписанный SECRET_KEY словарь, по умолчанию в куке у клиента.
- Подпись защищает от подмены, но не шифрует — храни только идентификаторы.
- flash — одноразовые сообщения, забираемые через get_flashed_messages.
Итог: куки дают HTTP память, session — удобный подписанный словарь в куке (виден, но не подделываем), flash — одноразовые сообщения. Это завершает блок про состояние; дальше переходим к базам данных.