Может ли клиент устанавливать куки самостоятельно
Что проверяют
Понимаете ли вы, что куки хранит и отправляет клиент, а значит, сервер не может доверять их содержимому. Бэкендеру на Python следом почти всегда задают вопрос, как тогда устроены сессии в Django или Flask и зачем нужны флаги HttpOnly, Secure и SameSite.
Как отвечать
Да, может, и тут важно разделить два вида клиентов.
Браузер ставит куку из JavaScript через document.cookie = "theme=dark; Path=/; Max-Age=86400", в браузерах на Chromium есть ещё асинхронный cookieStore.set(). Ограничения задаёт сам браузер:
HttpOnly: такую куку скрипт не видит и создать не может, её выставляет только сервер заголовкомSet-Cookie;- домен: скрипт ставит куку для своего домена или родительского, для чужого сайта нельзя;
- префикс
__Host-: такую куку браузер примет только сSecure,Path=/и безDomain, это защита от подмены с поддомена; - размер: около 4 КБ на одну куку.
Любой другой клиент отправляет что захочет: requests.get(url, cookies={"role": "admin"}) или curl -b. Поэтому значение куки для сервера это такой же пользовательский ввод, как тело запроса.
Практика на Python:
- Django: сессия по умолчанию хранит в куке только идентификатор, данные лежат на сервере. Для своих значений есть
response.set_signed_cookie()иrequest.get_signed_cookie(); - Flask: сессия целиком лежит в куке, она подписана
SECRET_KEY, но не зашифрована. Пользователь её прочитает, но не подделает; - флаги:
response.set_cookie("sid", value, httponly=True, secure=True, samesite="Lax")одинаково пишется во Flask и FastAPI.
Где спотыкаются
Хранят в куке роль или user_id без подписи и доверяют значению как есть. Любой клиент поменяет его за секунду.
Пишут, что клиент «должен ставить HttpOnly». Из JavaScript этот флаг выставить нельзя, он задаётся только ответом сервера.
Считают подписанную куку секретной. Подпись защищает от изменения, а не от чтения, поэтому пароли и персональные данные в неё не кладут.