Что такое токен CSRF? Каково его значение и как оно работает?

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

Ответ 1

Подделка межсайтовых запросов (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 с другого веб-сайта.

Ответ 2

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

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

Ответ 3

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

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

Ответ 4

В блоге Cloud Under есть хорошее объяснение токенов CSRF.

Представьте, что у вас есть веб-сайт, похожий на упрощенный 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). Не делай этого! Запросы на изменение данных могут быть представлены так же просто, как <img src="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 и DELETE, потому что, как объяснено выше, стандартная HTML-форма не может быть отправлена браузером используя эти методы.

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

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

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

Ответ 5

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