Уязвимость CSRF. Защита

20 комментариев

CSRF уязвимость Продолжаем цикл статей на тему уязвимости CSRF

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

В данной статье я попытаюсь рассказать о защите от атак данного типа со сторон:

  • Со стороны клиента — основные способы защитить себя самому
  • Со стороны сервера — правильное проектирование приложения

Если вам интересно как защититься от CSRF то добро пожаловать под кат.

Общая информация

В общем то хочу напомнить, CSRF — это НЕ уязвимость, это вид атаки. И данная атака проводится на конечного пользователя веб приложения с помощью уязвимости в данном приложении, которую можно назвать как «Отсутствие надлежащей проверки источника запроса» (название я придумал сам, не судите строго, но это так). Но здесь и далее я буду называть CSRF уязвимостью и атакой в одном лице так, как это проще, да и именно так принято =)

И раз атака проводится на пользователя, то и пользователю защищаться… шутка =) Дело в том что любой пользователь может снизить возможность проведения данной атаки на любом сайте, которым он пользуется (даже если на этих сайтах нет встроенной защиты от CSRF). Но помимо пользователей, сами разработчики сайтов могут спроектировать свое приложение так, чтобы недопустить возможность проведения данной атаки на своих пользователей.

Рассмотрим защиту с обоих сторон.

Защита со стороны пользователя

Вообщем тут все очень банально:

  • Не переходить на ссылки предложенные вам третьими лицами. Это самый банальный совет, я думаю это все и так знают, но решил лишний раз сказать об этом.
  • Деавторизовываться по окончанию работы с конкретным сайтом. Даже при наличии уязвимости, злоумшленник не сможет выполнить действия на целевом сайте от вашего имени.
  • Использовать отдельный браузер или «приватные или анонимные режимы» для работы с важными сайтами (в идеале использовать по одному браузеру на каждый сайт ^_^ а еще лучше отдельный компьютер :D).

На этом все. Теперь перейдем к главному.

Защита со стороны разработчиков

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

Проверка Referer

Сразу скажу, для тех кто читает статьи по диагонали. Основывать свою защиту только на проверке этого заголовка — плохо(!). Почему — см. далее.

Для начала разберемся, в чем заключается этот способ.

С сайтами мы работаем по HTTP протоколу. Каждый пакет этого протокола представляет собой набор заголовков + содержимое пакета. Одним из этих заголовков является Referer. Он содержит адрес источника перехода. Банальный пример: у вас открыт сайт A, на данном сайте вы кликаете на ссылку на сайт B, в этот момент при запросе в заголовке Referer будет содержатся адрес сайта A. То есть казалось бы это идеальный механизм для отслеживания откуда пришел пользователь.

А вот хрен. И дело здесь не в том что можно подделать реферер (какой здравомыслящий взломщик будет просить жертву о том, чтобы она подменила реферер и перешла по указанной ссылке). А в том что по моей статистике у около 5% пользователей передача Referer отключенна. То есть либо эти пять процентов не смогут работать с сайтом вообще, либо они будут уязвимы к этой атаке (зависит от политики вашего приложения).

Да, да, да, я знаю о чем вы подумали… Ну и фиг с этими 5%? Пусть будут уязвимы, зато остальные 95% защищены и при этом вы обошлись малой кровью. То есть если реферер содержит адрес нашего приложения либо пуст, то считаем источник подтвержденным? А вот снова хрен! Существуют варианты заставить браузер жертвы выполнить запрос без указания реферера (об этом я написал отдельную статью)! И вуаля! Оказывается все пользователи по-прежнему уязвимы.

Воощем как самостоятельный способ данный метод бессмыслен.

Подтверждение действия

Можно к каждой форме отправке прикрутить капчу, и показывать ее даже для зарегестрированных пользователей, чтобы спасти их от CSRF… Хотя пожалуй, я бы предпочел отдать свой аккаунт хакеру, чем работать в такой системе…

Токены

Ну и теперь единственный правильный и надежный способ.

Смысл данного способа заключается в добавлении параметра содержащего некоторый «токенов» к каждой ссылке, форме отправки и проч. А при получении запроса сервер должен проверять наличие данного токена в принятых параметрах. Естественно каждый токен для каждого пользователя должен быть уникальным, а еще лучше если каждый токен будет уникальным.

Один из самых простых и надежных примеров реализации — токен генерируется при каждом запросе новый и устанавливается в cookies пользователя а также добавляется в параметры форм и ссылок на странице:

И затем при получении каждого запроса сравнивается токен из куков и токен указанный в параметрах формы. И если они одинаковы, то источник запроса легален. Затем токен генерируется снова, и снова устанавливается в куки, и т.д. по кругу.

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

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

Вывод

Надеюсь из данной статьи вы поняли каким образом следует защищаться от CSRF атак.

Читайте также:

  1. Уязвимость CSRF. Введение
  2. Уязвимость CSRF. Защита
  3. Уязвимость CSRF. Скрываем Referer при редиректе

PS: продолжение следует :)

  1. Александр

    Хотелось бы отметить следующее: автор статьи упоминает капчу как один из способов защиты от CSRF, критикуя только ее неудобство для пользователя. Однако, следует учитывать то, что капчи изначально не предназначены для этого и, в большинстве своем, не защищают от CSRF (за некоторым исключением). Причина станет ясна, если знать механизм работы капч и немного подумать.

    1. Дмитрий Амиров Автор

      Ну чтож, давайте попробуем с вами подискутировать на эту тему. Допустим я знаю как работает капча (заметьте у меня в блоге есть почти целый раздел, ей посвещенный).

      Реализация капчи может быть разной, и, наверное, правильней будет сказать, что большинство ее реализаций все же сможет защитить от CSRF (за некоторым исключением). Ну и опять же если глянуть следующее предложение идущее под заголовком «Токены»: Ну и теперь единственный правильный и надежный способ.. Я думаю, это предложение должно натолкнуть на мысль, что все же идея с капчами не совсем разумна) — в контексте статьи, это всего лишь пример нестандартного мышления.

      Ну а говорить о том что некоторые реализации капчи не смогут защитить от CSRF… Ну тут уж извините. Это ошибка программиста, реализовавшего дырявую капчу. И уж никак не проблема последней. С таким же успехом можно говорить и про токены, мол оные бесполезны «если знать механизм работы токенов и немного подумать».

  2. Маэстро

    токен генерируется при каждом запросе новый и устанавливается в cookies пользователя

    Не совсем ясно, зачем Вы токен сохраняете в куке? Если для того, чтобы потом с помощью javascript взять его из куки и подставить в форму (или ajax-запрос), то это вступает в конфликт с другим методом защиты, который заключается в том, что на сервере включают флаг «httponly» на формирование куки. Если флаг включен, то браузер не позволит получить значение куки с помощью javascript и передать на сервер, т.е. токен будет пуст.

    1. Дмитрий Амиров Автор

      Если куки у пользователя отключены, то сама атака CSRF по большому счету бессмыслена. Атака обычно происходит на авторизванного пользователя. Те у кого куки отключены — врятли смогут авторизоваться.

      1. Иван

        Авторизация и аутентификация возможны на сессиях и без использования куки

        1. Дмитрий Амиров Автор

          Сессии без использования кук? Если вы о стандартном механизме сессий php, то идентификатор этой сессии также хранится в куках. Нет куков — нет сессий.

          Второй вариант подставлять идентификатор сессий во все запросы всех форм и ссылок, стандартный механизм php это тоже вроде как поддерживает. Но такой вариант фактически не уязвим к атакам CSRF. Подумайте почему.

          1. Алексей

            Например Auth http не требует включенных кук. а в html5 отключить передачу реферера можно без использования javascript.

  3. Дмитрий

    Эх … помогите лучше фрагмент запроса &etext= расшифровать, который остается в REFERER после прихода пользователя из поиска Yandex.

  4. Utka

    Один из самых простых и надежных примеров реализации — токен генерируется при каждом запросе новый и устанавливается в cookies пользователя а также добавляется в параметры форм и ссылок на странице:

    Все правильно, защиту нужно делать только токеном, но за чем каждый раз генерировать новый токен и класть его в куку?

    Можно создать уникальный хэш для каждого пользователя при авторизации и отправлять его с постом, а уже на сервере сравнивать из базы этот хэш с тем что пришел в посте. Важно здесь только чтобы ключ был уникальным для каждой сессии авторизации. Или я не прав?

    Просто не пойму на кой в куках хранить не нужные вещи?

    1. Дмитрий Амиров Автор

      Ну хранение токена в куке — вещь не принципиальная. Это просто проще чем хранить его в базе. Обратите внимание я писал:

      Один из самых простых и надежных…

      Можно хранить его и в базе. В принципе пофиг абсолютно… Можно и не хранить его вообще нигде, а генерировать на основе уникальных данных юзера, и какой нибудь секретной серверной соли.

      Вариантов то масса, в статье указан единственный из них :)

  5. Дмитрий

    Добрый день. Подскажите, как токены, прописанные в коде страницы, защищают от csrf? Почему злоумышоенник не сможет спарсить сам токен и передать в post запросе?

    1. Дмитрий Амиров Автор

      Злоумышленник не парсит целевую страницу, и ничего не знает о ее содержимом. На целевую страницу пользователь лишь перенаправляется злоумышленником. А так как злоумышленник не знает токен, он не может перенаправить на правильный адрес с токеном.

      1. Андрей

        Парсим одну из страниц на сайте вытягиваем токен и следующим шагом отправляемм на нужную команду уже с токеном.
        В чем защита?

        А я то думаю почему некоторые сервисы иногда просят ввести пароль при совершении важных операций, вот это защита.

        1. Дмитрий Амиров Автор

          Вы видимо невнимательно читали о том в чем заключается сама атака. У злоумышленника нет возможности спарсить токен. Токен для каждого пользователя уникален.

          Повторный вод пароля — защита от других проблем.

        2. Алексей

          Как ты спарсишь если у каждого пользователя разные токен? бывает что токен генерируется в момент вывода формы пользователю и пишется ему в сессию, спасет только распарсивание формы на стороне посетителя — а это не возможно.

          есть кстати более простые способы защитится правильно настроив сервер, но только один сайт из 100 тыс это делает.

Добавить комментарий

Прочли запись? Понравилась? Не стесняйтесь, оставьте, пожалуйста, свой комментарий. Мне очень интересно, что вы думаете об этом. Кстати в комментарии вы можете задать мне любой вопрос. Я обязательно отвечу.

Вы можете оставить коментарий анонимно, для этого можно не указывать Имя и email. Все комментарии проходят модерацию, поэтому ваш комментарий появится не сразу.