Я пытаюсь понять всю проблему с CSRF и соответствующие способы предотвратить это. (Ресурсы, которые я прочитал, понимаю и с которыми согласен: Шпаргалка по профилактике OWASP CSRF , Вопросы о CSRF .)
Насколько я понимаю, уязвимость вокруг CSRF вводится в предположении, что (с точки зрения веб-сервера) действительный файл cookie сеанса во входящем HTTP-запросе отражает пожелания аутентифицированного пользователя. Но все файлы cookie для домена происхождения магически связаны с запросом браузера, поэтому на самом деле все, что сервер может сделать вывод из наличия действительного файла cookie сеанса в запросе, состоит в том, что запрос поступает от браузера, который имеет аутентифицированный сеанс; он больше не может предполагать что-либо о кодеработает в этом браузере, или действительно ли он отражает пожелания пользователя. Способ предотвратить это состоит в том, чтобы включить в запрос дополнительную информацию для аутентификации («токен CSRF»), передаваемую с помощью других средств, помимо автоматической обработки файлов cookie браузером. Проще говоря, cookie сеанса аутентифицирует пользователя / браузера, а токен CSRF аутентифицирует код, выполняемый в браузере.
Таким образом, в двух словах: если вы используете cookie-файл сеанса для аутентификации пользователей вашего веб-приложения, вы также должны добавить токен CSRF к каждому ответу и требовать соответствующий токен CSRF в каждом (мутирующем) запросе. Затем токен CSRF отправляется обратно от сервера к браузеру обратно на сервер, доказывая серверу, что страница, выполняющая запрос, одобрена (сгенерирована даже этим сервером).
На мой вопрос, который касается конкретного метода транспорта, используемого для этого токена CSRF в этом двустороннем сообщении.
Кажется распространенным (например, в AngularJS , Django , Rails ) отправлять токен CSRF с сервера клиенту в виде файла cookie (т. Е. В заголовке Set-Cookie), а затем иметь Javascript на клиенте, вычищать его из файла cookie и прикреплять его в качестве отдельного заголовка XSRF-TOKEN для отправки обратно на сервер.
(Альтернативным методом является метод, рекомендованный, например, Express , в котором токен CSRF, сгенерированный сервером, включается в тело ответа через расширение шаблона на стороне сервера, присоединяется непосредственно к коду / разметке, которая будет передавать его обратно на сервер, например, в качестве скрытой формы ввода. Этот пример представляет собой более привычный веб-способ ведения дел, но в целом подходит для более тяжелого JS-клиента.)
Почему так часто используют Set-Cookie в качестве нисходящего транспорта для токена CSRF / почему это хорошая идея? Я полагаю, что авторы всех этих фреймворков тщательно продумали свои варианты и не ошиблись. Но на первый взгляд использование cookie-файлов для обхода того, что по сути является ограничением дизайна cookie-файлов, кажется глупым. Фактически, если вы использовали файлы cookie в качестве транспорта туда и обратно (заголовок Set-Cookie: вниз по течению, чтобы сервер сообщал браузеру токен CSRF, и заголовок Cookie: вверх по течению, чтобы браузер возвратил его на сервер), вы бы снова представили уязвимость, которую вы пытаемся исправить.
Я понимаю, что вышеупомянутые фреймворки не используют куки-файлы для полного обхода токена CSRF; они используют Set-Cookie в нисходящем направлении, а затем что-то еще (например, заголовок X-CSRF-Token) в восходящем направлении, и это закрывает уязвимость. Но даже использование Set-Cookie в качестве нижестоящего транспорта потенциально вводит в заблуждение и опасно; теперь браузер будет прикреплять токен CSRF к каждому запросу, включая подлинные вредоносные запросы XSRF; в лучшем случае это делает запрос больше, чем нужно, а в худшем случае какой-то благонамеренный, но ошибочный кусок серверного кода может попытаться его использовать, что было бы очень плохо. И далее, поскольку фактическим предполагаемым получателем токена CSRF является клиентский Javascript, это означает, что этот файл cookie не может быть защищен только с помощью http.
Ответы:
Хорошая причина, к которой вы обращаетесь, заключается в том, что после получения файла cookie CSRF он становится доступным для использования в приложении в клиентском скрипте для использования как в обычных формах, так и в AJAX POST. Это будет иметь смысл в тяжелом JavaScript-приложении, например, используемом AngularJS (использование AngularJS не требует, чтобы приложение было одностраничным приложением, поэтому было бы полезно, когда состояние должно передаваться между различными запросами страницы, где значение CSRF не может нормально сохраняться в браузере).
Рассмотрите следующие сценарии и процессы в типичном приложении для некоторых плюсов и минусов каждого подхода, который вы описываете. Они основаны на шаблоне токена синхронизатора .
Подход к телу запроса
Преимущества:
Недостатки:
Пользовательский заголовок HTTP (нисходящий)
Преимущества:
Недостатки:
Пользовательский заголовок HTTP (восходящий)
Преимущества:
Недостатки:
Пользовательский заголовок HTTP (восходящий и нисходящий)
Преимущества:
Недостатки:
Set-Cookie
Преимущества:
Недостатки:
Таким образом, подход с использованием файлов cookie является довольно динамичным, предлагая простой способ извлечь значение cookie (любой запрос HTTP) и использовать его (JS может автоматически добавлять значение в любую форму и использовать его в запросах AJAX либо в качестве заголовка, либо в виде значение формы). Как только токен CSRF был получен для сеанса, нет необходимости восстанавливать его, поскольку у злоумышленника, использующего эксплойт CSRF, нет способа извлечь этот токен. Если злонамеренный пользователь пытается прочитать токен CSRF пользователя любым из указанных выше способов, это будет предотвращено той же политикой происхождения . Если злонамеренный пользователь пытается получить серверную часть токена CSRF (например, через
curl
) тогда этот токен не будет связан с той же учетной записью пользователя, что и файл cookie сеанса аутентификации жертвы, будет отсутствовать в запросе (это будет злоумышленник - следовательно, он не будет связан на стороне сервера с сеансом жертвы).Наряду с шаблоном токена синхронизатора существует также файл cookie Double Submit.Метод предотвращения CSRF, который, конечно, использует куки для хранения типа токена CSRF. Это легче реализовать, так как для маркера CSRF не требуется никакого состояния на стороне сервера. Маркер CSRF фактически может быть стандартным файлом cookie аутентификации при использовании этого метода, и это значение передается с помощью файлов cookie, как обычно, с запросом, но значение также повторяется либо в скрытом поле, либо в заголовке, который злоумышленник не может воспроизвести как они не могут прочитать значение в первую очередь. Однако рекомендуется выбрать другой файл cookie, отличный от файла cookie для аутентификации, чтобы файл cookie для аутентификации можно было защитить, помечая HttpOnly. Так что это еще одна распространенная причина, по которой вы можете найти предотвращение CSRF, используя метод, основанный на cookie.
источник
Использование файла cookie для предоставления токена CSRF клиенту не позволяет выполнить успешную атаку, поскольку злоумышленник не может прочитать значение файла cookie и, следовательно, не может поместить его там, где этого требует проверка CSRF на стороне сервера.
Злоумышленник сможет вызвать запрос к серверу с использованием файла cookie с токеном авторизации и файла CSRF в заголовках запроса. Но сервер не ищет маркер CSRF как cookie в заголовках запроса, он ищет полезную нагрузку запроса. И даже если злоумышленник знает, куда поместить токен CSRF в полезную нагрузку, ему придется прочитать его значение, чтобы поместить его туда. Но политика браузера, основанная на разных источниках, предотвращает чтение любых значений cookie с целевого веб-сайта.
Та же логика не применима к куки-файлу аутентификационного токена, поскольку сервер ожидает его в заголовках запроса, и злоумышленнику не нужно делать ничего особенного, чтобы поместить его туда.
источник
src='bank.com/transfer?to=hacker&amount=1000
которого запрашивает браузер, вместе с соответствующими файлами cookie для этого сайта (bank.com
)?Мое лучшее предположение относительно ответа: рассмотрите эти 3 варианта, как передать токен CSRF с сервера в браузер.
Я думаю, что первое, тело запроса (хотя оно продемонстрировано в учебном пособии по Express, на которое я ссылался в этом вопросе ), не столь переносимо в самых разных ситуациях; не каждый генерирует каждый HTTP-ответ динамически; когда вам в конечном итоге понадобится поместить токен в сгенерированный ответ, он может сильно различаться (при вводе скрытой формы; во фрагменте кода JS или переменной, доступной для другого кода JS; возможно, даже в URL, хотя это обычно кажется плохим местом поставить токены CSRF). Так что # 1, хотя и работающий с некоторой настройкой, является трудным местом для подхода, который подходит всем.
Второй, пользовательский заголовок, привлекателен, но на самом деле не работает, потому что, хотя JS может получить заголовки для вызванного XHR, он не может получить заголовки для страницы, с которой он загружен .
Это оставляет третий файл cookie, содержащийся в заголовке Set-Cookie, в качестве подхода, который легко использовать в любых ситуациях (любой сервер сможет устанавливать заголовки файлов cookie для каждого запроса, и не имеет значения, какого рода данные находятся в теле запроса). Таким образом, несмотря на свои недостатки, это был самый простой способ для широкого применения фреймворков.
источник
Помимо сессионных куки-файлов (что является стандартным), я не хочу использовать дополнительные куки-файлы.
Я нашел решение, которое работает для меня при создании одностраничного веб-приложения (SPA) со многими запросами AJAX. Примечание: я использую серверную Java и клиентскую JQuery, но никаких волшебных вещей, поэтому я думаю, что этот принцип может быть реализован на всех популярных языках программирования.
Мое решение без лишних файлов cookie простое:
Сторона клиента
Сохраните токен CSRF, который возвращается сервером после успешного входа в систему, в глобальной переменной (если вы хотите использовать веб-хранилище вместо глобального, конечно, это нормально). Поручите JQuery указывать заголовок X-CSRF-TOKEN в каждом вызове AJAX.
Главная страница «указателя» содержит этот фрагмент JavaScript:
Сторона сервера
При успешном входе в систему создайте случайный (и достаточно длинный) токен CSRF, сохраните его в сеансе на стороне сервера и верните его клиенту. Отфильтруйте определенные (конфиденциальные) входящие запросы, сравнив значение заголовка X-CSRF-TOKEN со значением, сохраненным в сеансе: они должны совпадать.
Чувствительные AJAX-вызовы (POST form-data и GET JSON-data) и серверный фильтр, перехватывающий их, находятся в пути / dataservice / *. Запросы на вход в систему не должны попадать в фильтр, поэтому они находятся на другом пути. Запросы на ресурсы HTML, CSS, JS и изображения также не находятся в пути / dataservice / *, поэтому не фильтруются. Они не содержат ничего секретного и не могут причинить вреда, так что это нормально.
источник