Что такое токен CSRF? Каково его значение и как оно работает? - PullRequest
512 голосов
/ 06 марта 2011

Я пишу приложение (Django, так бывает), и я просто хочу понять, что на самом деле представляет собой «токен CSRF» и как он защищает данные.Являются ли почтовые данные небезопасными, если вы не используете токены CSRF?

Ответы [ 5 ]

1318 голосов
/ 20 ноября 2015

Подделка межсайтовых запросов (CSRF) простыми словами

  • Предположим, вы в настоящее время вошли в свой онлайн-банкинг на www.mybank.com
  • Предположим, перевод денег с mybank.com приведет к запросу (концептуально) формы http://www.mybank.com/transfer?to=<SomeAccountnumber>;amount=<SomeAmount>. (Ваш номер счета не нужен, поскольку он подразумевается вашим логином.)
  • Вы посещаете www.cute-cat-pictures.org, не зная, что это вредоносный сайт.
  • Если владелец этого сайта знает форму вышеуказанного запроса (просто!) И правильно догадывается, что вы вошли в систему mybank.com (требует некоторой удачи!), Они могут включить на своей странице запрос, подобный http://www.mybank.com/transfer?to=123456;amount=10000 ( где 123456 - это номер их счета на Каймановых островах, а 10000 - это сумма, которую вы ранее считали рад обладать).
  • Вы получили эту страницу www.cute-cat-pictures.org, поэтому ваш браузер выполнит этот запрос.
  • Ваш банк не может распознать источник этого запроса: ваш веб-браузер отправит запрос вместе с файлом cookie www.mybank.com, и он будет выглядеть вполне законно. Там идут ваши деньги!

Это мир без токенов CSRF .

Теперь к лучшему с токенами CSRF :

  • Запрос на перенос расширен с помощью третьего аргумента: http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971.
  • Этот токен - это огромное, не поддающееся догадке случайное число, которое mybank.com включит на своей веб-странице, когда предоставит его вам. Это отличается каждый раз, когда они кому-либо предоставляют какую-либо страницу.
  • Злоумышленник не может угадать токен, не может убедить ваш веб-браузер отказаться от него (если браузер работает правильно ...), и поэтому злоумышленник не сможет создайте действительный запрос, потому что запросы с неправильным токеном (или без токена) будут отклонены www.mybank.com.

Результат: Вы сохраняете свои 10000 денежных единиц. Я предлагаю вам пожертвовать это в Википедию.

(Ваш пробег может отличаться.)

РЕДАКТИРОВАТЬ из комментария стоит прочитать:

Стоит отметить, что скрипт из www.cute-cat-pictures.org обычно не имеет доступа к вашему токену анти-CSRF из www.mybank.com из-за контроля доступа HTTP. Это примечание важно для некоторых людей, которые необоснованно отправляют заголовок Access-Control-Allow-Origin: * для каждого ответа веб-сайта, не зная, для чего он нужен, просто потому, что они не могут использовать API с другого веб-сайта.

214 голосов
/ 06 марта 2011

Да, почтовые данные в безопасности.Но происхождение этих данных не так.Таким образом, кто-то может заставить пользователя с помощью JS войти на ваш сайт, просматривая веб-страницу злоумышленника.

Чтобы предотвратить это, django отправит случайный ключ как в файле cookie, так и в данных формы.Затем, когда пользователи отправляют сообщения POST, он проверяет, идентичны ли два ключа.В случае обмана пользователя сторонний веб-сайт не может получить файлы cookie вашего сайта, что приводит к ошибке аутентификации.

69 голосов
/ 06 марта 2011

Сайт генерирует уникальный токен при создании страницы формы.Этот токен необходим для отправки / получения данных на сервер.

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

19 голосов
/ 22 марта 2018

Позвольте привести пример ...

Представьте, что у вас есть такой сайт, как упрощенный Twitter, размещенный на a.com. Зарегистрированные пользователи могут вводить некоторый текст (твит) в форму, которая отправляется на сервер в виде запроса POST и публикуется при нажатии кнопки отправки. На сервере пользователь идентифицируется cookie-файлом, содержащим его уникальный идентификатор сеанса, поэтому ваш сервер знает, кто опубликовал твит.

Форма может быть такой простой:

 <form action="http://a.com/tweet" method="POST">
 <input type="text" name="tweet">
 <input type="submit">
 </form>

А теперь представьте, что плохой парень копирует и вставляет эту форму на свой вредоносный веб-сайт, скажем, на b.com. Форма все еще будет работать. Пока пользователь входит в ваш Твиттер (т. Е. У него есть действующий файл cookie сеанса для a.com), запрос POST будет отправляться на http://a.com/tweet и обрабатываться как обычно, когда пользователь нажимает кнопку подтверждения. кнопка.

Пока что это не является большой проблемой, пока пользователь осведомлен о том, что именно делает форма, но что если наш плохой парень подправит форму следующим образом:

 <form action="https://example.com/tweet" method="POST">
 <input type="hidden" name="tweet" value="Buy great products at 
 http://b.com/#iambad">
 <input type="submit" value="Click to win!">
 </form>

Теперь, если один из ваших пользователей попадет на сайт злоумышленника и нажмет кнопку «Нажми, чтобы выиграть!», Форма будет отправлена ​​на ваш сайт, пользователь будет правильно идентифицирован по идентификатору сеанса в файле cookie и скрытый твит публикуется.

Если бы нашему плохому парню было еще хуже, он заставил бы невинного пользователя отправить эту форму, как только они откроют его веб-страницу с помощью JavaScript, возможно, даже полностью скрытого в невидимом фрейме. В основном это подделка межсайтовых запросов.

Форма может быть легко отправлена ​​отовсюду. Обычно это общая черта, но во многих случаях важно разрешить отправку формы только из домена, к которому она принадлежит.

Еще хуже, если ваше веб-приложение не различает запросы POST и GET (например, в PHP с использованием $ _REQUEST вместо $ _POST). Не делай этого! Запросы на изменение данных можно отправить так же просто, как http://a.com/tweet?tweet=This+is+really+bad,, встроенный в вредоносный веб-сайт или даже в электронное письмо.

Как сделать так, чтобы форму можно было отправлять только с моего собственного сайта? Вот где появляется токен CSRF. Маркер CSRF - это случайная, трудно угадываемая строка. На странице с формой, которую вы хотите защитить, сервер сгенерирует случайную строку, токен CSRF, добавит ее в форму в качестве скрытого поля и также каким-то образом запомнит, либо сохранив ее в сеансе, либо установив cookie содержащий значение. Теперь форма будет выглядеть так:

    <form action="https://example.com/tweet" method="POST">
    <input type="hidden" name="csrf-token" 
    value="nc98P987bcpncYhoadjoiydc9ajDlcn">
    <input type="text" name="tweet">
    <input type="submit">
    </form>

Когда пользователь отправляет форму, сервер просто должен сравнить значение отправленного поля csrf-token (имя не имеет значения) с токеном CSRF, запомненным сервером. Если обе строки равны, сервер может продолжить обработку формы. В противном случае сервер должен немедленно прекратить обработку формы и ответить ошибкой.

Почему это работает? Есть несколько причин, по которым злоумышленник из нашего примера не может получить токен CSRF:

Копирование статического исходного кода с нашей страницы на другой веб-сайт было бы бесполезным, поскольку значение скрытого поля меняется с каждым пользователем. Если бы сайт злоумышленника не знал токен CSRF текущего пользователя, ваш сервер всегда отклонял бы запрос POST.

Поскольку вредоносная страница злоумышленника загружается браузером вашего пользователя из другого домена (b.com вместо a.com), у злоумышленника нет шансов написать код JavaScript, который загружает контент и, следовательно, текущий пользователь CSRF токен с вашего сайта. Это связано с тем, что веб-браузеры по умолчанию не разрешают междоменные запросы AJAX.

Плохой парень также не может получить доступ к куки, установленному вашим сервером, потому что домены не будут совпадать.

Когда мне следует защищать от подделки межсайтовых запросов? Если вы можете быть уверены, что не смешиваете GET, POST и другие методы запроса, как описано выше, хорошим началом будет защита всех запросов POST по умолчанию.

Вам не нужно защищать PUT иУДАЛИТЬ запросы, потому что, как объяснялось выше, стандартная HTML-форма не может быть отправлена ​​браузером с использованием этих методов.

С другой стороны, JavaScript действительно может делать другие типы запросов, например, с помощью функции jQuery $ .ajax (), но помните, чтобы запросы AJAX работали, домены должны совпадать (если только вы явно не настраиваете свой веб-сервер).

Это означает, что часто вам даже не нужно добавлять токен CSRF в запросы AJAX, даже если они являются запросами POST, но вам нужно будет убедиться, что вы обходите проверку CSRF только в своем веб-приложении, если запрос POST на самом деле запрос AJAX. Вы можете сделать это, посмотрев на наличие заголовка типа X-Requested-With, который обычно включают в себя запросы AJAX. Вы также можете установить другой пользовательский заголовок и проверить его наличие на стороне сервера. Это безопасно, поскольку браузер не будет добавлять пользовательские заголовки к обычной отправке формы HTML (см. Выше), поэтому у мистера Плохого парня нет шансов смоделировать это поведение с помощью формы.

Если у вас есть сомнения по поводу запросов AJAX, потому что по какой-то причине вы не можете проверить заголовок, такой как X-Requested-With, просто передайте сгенерированный токен CSRF в свой JavaScript и добавьте токен в запрос AJAX. Есть несколько способов сделать это; либо добавьте его в полезную нагрузку, как обычная форма HTML, либо добавьте пользовательский заголовок в запрос AJAX. Пока ваш сервер знает, где искать его во входящем запросе и может сравнить его с исходным значением, которое он запоминает из сеанса или файла cookie, вы отсортированы.

5 голосов
/ 06 марта 2011

Корень всего этого - убедиться, что запросы поступают от реальных пользователей сайта. Токен csrf создается для форм и должен быть привязан к сеансам пользователя. Используется для отправки запросов на сервер, на котором токен их проверяет. Это один из способов защиты от csrf, другой - проверка заголовка реферера.

...