LINUX.ORG.RU

CSRF vs «[X] Remember me»

 , ,


0

1

И так и эдак кручу, и всякую дичь про «Remember me»-куку читаю, и всё равно ни с какого боку не могу понять, каким образом галка «Remember me» в принципе может быть совместима с защитой от CSRF.

Там же вся идея в том, что при редиректе/сабмите с bad.com на good.com, браузер передаст куки good.com и залогинет юзера. Какая разница, будет там простенький session id или навороченная хрень? Оба же передадутся, оба залогинят юзера, и привет CSRF. Разница НЯП только в невозможности брутфорса навороченного session id.

Единственный способ защиты от CSRF – вообще не использовать куки, гнать session id вручную (заголовком или в теле), но тогда сессия теряется при закрытии вкладки. И при открытии внутренней ссылки в новой вкладке – тоже теряется.

UPD. В общем, похоже всё упирается в «ослабленную версию защиты», где GET не требует токена, но может его возвращать, чтобы потом сайт передавал его с POST. А внешний сайт-контроллер не сможет выдрать токен из GET-ответа, чтобы подсунуть его в POST.



Последнее исправление: pr849 (всего исправлений: 3)

Там же вся идея в том, что при редиректе/сабмите с bad.com на good.com, браузер передаст куки good.com и залогинет юзера.

А ты все же почитай как работает CSRF. Именно от этого он и защищает, если грамотно реализован в приложении (сайта)

каким образом галка «Remember me» в принципе может быть совместима с защитой от CSRF.

Ты опять путаешь теплое с мягким. Сессионные куки будут использоваться в любом случае. Remember me запоминает сессию пользователя в БД на стороне сайте

router ★★★★★
()

Можно сделать так, чтобы одной куки было достаточно лишь для GET запросов. По всем стандартам они не должны приводить к изменению состояния сервера, так что от того что левый сайт сможет сделать авторизованный GET запрос ничего плохого не случится, ведь прочитать ответ он не сможет, а никаких модификаций в учётной записи пользователя выполнено не будет.

Для POST/PUT/PATCH/DELETE запросов, которые уже потенциально опасны даже без доступа к ответу сервера, можно требовать передавать токен не в куке, а, например, в заголовке Authorization, куда его будет подсовывать клиентский JS, который будет этот токен получать с помощью GET запросов или читать из localStorage. Соответственно, строннему сайту этот токен будет недоступен и он добавить этот заголовок не сможет с валидным токеном.

Если сайт без JS, то бекэнд сам может добавлять в формы скрытый input с дополнительным токеном потом этим же бекэндом и проверяемым, без которого форма считает недействительной и не обрабатывается бекэндом. Опять же, этот дополнительный токен не может получить другой сайт, так как для него надо прочитать ответ сервера на запрос, который возвращает HTML-код формы.

Кстати, если очень лень, можно добавлять тот же токен, что и лежит в куке, а на бекэнде просто сравнивать токен из куки и токен переданный в дополнительном заголовке или скрытом поле формы (разумеется, токен из куки валидируется стандартым образом). Так как сторонний сайт не сможет прочитать куку, чтобы достать оттуда токен и добавить его в заголовок или форму. Но в этом случае отпадает возможность использовать HTTP-only куки (защита от угона сессии с помощью XSS), так что подход имеет не только плюсы, но минусы. В идеале должно быть два разных токена.

сессия теряется при закрытии вкладки

С чего бы ей теряться. Если хочется длительных сессий, то токен можно сохранить в localStorage (вечная сессия, если только юзер не удалит принудительно данные сайта) или sessionStorage (сессия до закрытия последней вкладки браузера, но доступная во всех открытых вкладках сайта включая новые). Если хочется, чтобы сессия имела срок действия как куки, то можно использовать JWT или аналог, которые бекэнд будет генерировать с нужным сроком действия и проверять при каждом запросе.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 6)
Ответ на: комментарий от KivApple

Спасибо.

от того что левый сайт сможет сделать авторизованный GET запрос ничего плохого не случится, ведь прочитать ответ он не сможет, а никаких модификаций в учётной записи пользователя выполнено не будет.

Вот этот момент я сам в уме нормально проговорить не осилил.

pr849
() автор топика
Ответ на: комментарий от router

Remember me запоминает сессию пользователя в БД на стороне сайте

Remember me влияет на срок жизни куки выданной бекэндом браузеру в ответ на успешную авторизацию. Если у куки не указан срок жизни, то она удаляется при закрытии браузера. Если у куки есть срок жизни, то она не удаляется до его истечения (при этом у современных браузеров есть ограничение на максимальный срок жизни куки, чуть больше года).

Со стороны бекэнда обычно разницы особой нет. Выданные токены всё равно надо хранить в базе, даже если галка remember me не была выбрана. Ведь бекэнду нужно отвечать на последующие запросы до закрытия окна браузера (юзер может переходить между страницами сайта, отправлять формы и т. д., не закрывая браузер и его сессия должна жить), а значит ему нужно куда-то запомнить выданный во время авторизации токен, чтобы валидировать в будущем, иначе юзеру придётся вводить логин-пароль на каждую операцию даже в рамках одной сессии.

Если сайт использует вместо куки localStorage, то снятая галка может переключить клиентский JS на использование sessionStorage (чтобы токен забылся при закрытии браузера), при этом бекэнд даже не узнает об этом.

Разве что если у нас JWT, то бекэнду нужно знать какой срок жизни ему выставить при генерации и тут Remember me может влиять (с другой стороны, выданные JWT могут не храниться в БД и если Remember me стоит, так что опять неверно). Но, опять же, этот токен нужно куда-то сохранить на клиенте (в куку или один из видов стораджей в браузере). И Remember me может влиять на параметры этого хранения (срок жизни куки, выбор между localStorage и sessionStorage). И даже должен влиять, потому что мы можем хотеть, чтобы сессия закрывалась при закрытии браузера, а не по таймауту или не только по таймауту. А бекэнд отследить закрытие браузера не может, только попросить сам браузер об этом.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 6)
Ответ на: комментарий от router

Он применяется по умолчанию. Если сервер не передаёт CORS заголовки (а дефолтные конфигурации серверов их не включают), то браузер не даёт выполнять большинство кроссдоменных запросов.

И большинству сайтов это вполне приемлемо, так как у них всё на одном домене.

CORS нужен для межсайтовой интеграции. Типа для какого-нибудь VK API, чтобы сторонние сайты могли добавлять функции типа «запостить мою ачивку в браузерке на стену» (для этого JS на сайте браузерки нужно будет дёрнуть API на домене VK и потребуется CORS). Это не частый use-case, большинство приложений не предоставляют API другим сайтам, так ещё и клиентский.

KivApple ★★★★★
()
Последнее исправление: KivApple (всего исправлений: 4)