Защита от CSRF

Определение CSRF

Cross-Site Request Forgery (CSRF) — это тип атаки, при котором злоумышленник заставляет пользователя выполнить нежелательное действие на веб-сайте, где он уже авторизован. Атака обычно включает отправку подложных запросов от имени пользователя, что может привести к несанкционированным изменениям данных, например, переводам средств, изменениям паролей или публикациям сообщений. Эти запросы часто отправляются без ведома пользователя и используют его текущую сессию.

Принцип работы CSRF

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

Механизмы защиты от CSRF

Для защиты от CSRF-атак применяются различные методы, направленные на проверку подлинности запросов. Рассмотрим основные из них.

1. Использование токенов CSRF

Самым популярным методом защиты является использование уникальных токенов, которые отправляются вместе с запросами. Эти токены генерируются сервером для каждого сеанса пользователя и привязываются к его сессии. Когда клиент отправляет запрос (например, через форму или AJAX), токен CSRF должен быть передан вместе с запросом в теле или заголовках.

Сервер проверяет токен на подлинность, сверяя его с тем, который был сгенерирован для текущей сессии. Если токен не совпадает или отсутствует, запрос отклоняется. Этот метод гарантирует, что запрос пришел от доверенного источника, а не от злоумышленника.

Пример реализации с использованием Jav * aScript:

// Генерация токена на стороне сервера (например, через middleware в Express)
app.use((req, res, next) => {
  res.locals.csrfToken = generateCsrfToken();  // генерируется уникальный токен
  next();
});

// Вставка токена в форму на клиентской стороне
document.querySelector('form').innerHTML += `<input type="hidden" name="csrf_token" value="${res.locals.csrfToken}">`;

// Отправка запроса с токеном через AJAX
const csrfToken = document.querySelector('input[name="csrf_token"]').value;
fetch('/submit', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRF-Token': csrfToken  // передача токена в заголовке
  },
  body: JSON.stringify({ data: 'value' })
});
2. Проверка источника запросов (Referer и Origin)

Другим методом защиты является проверка заголовков Referer и Origin. Эти заголовки указывают на источник запроса, и если запрос приходит с подозрительного источника (например, с другого домена), сервер может отклонить его. Однако этот метод не является полностью надежным, так как заголовки могут быть подделаны.

Пример:

const origin = req.get('Origin');
const referer = req.get('Referer');

if (origin !== 'https://trusteddomain.com' || referer !== 'https://trusteddomain.com') {
  res.status(403).send('Forbidden');
  return;
}

Этот метод эффективен при правильной настройке, но не всегда может обеспечить 100% защиту, так как некоторые браузеры могут не отправлять эти заголовки.

3. SameSite Cookies

Особенность CSRF-атак заключается в том, что они часто используют cookies для аутентификации, так как браузеры автоматически отправляют cookies с каждым запросом. Чтобы уменьшить уязвимость, можно использовать атрибут SameSite для cookies. Этот атрибут ограничивает передачу cookies только для запросов с того же домена, что и сайт, тем самым блокируя возможность использования cookies для атак с другого домена.

Существует три значения для атрибута SameSite:

  • Strict: Cookies отправляются только при прямом переходе с того же сайта. Запросы с других сайтов не будут включать cookies.
  • Lax: Cookies отправляются с безопасных запросов, таких как переходы по ссылке, но не с других типов запросов, например, AJAX.
  • None: Cookies отправляются с любыми запросами, но требуют наличия флага Secure (т.е. cookies будут передаваться только через HTTPS).

Пример:

document.cookie = "session_id=12345; SameSite=Strict; Secure";

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

4. Заголовки X-Requested-With

Еще один способ защиты от CSRF-атак — это проверка заголовка X-Requested-With. Этот заголовок обычно добавляется библиотеками AJAX (например, jQuery) при отправке асинхронных запросов. Сервер может проверять наличие этого заголовка в запросах, чтобы убедиться, что они были инициированы клиентом (например, веб-страницей), а не внешним злоумышленником.

Пример:

if (req.get('X-Requested-With') !== 'XMLHttpRequest') {
  res.status(400).send('Invalid request');
  return;
}

Этот метод является простым, но он также имеет свои ограничения: злоумышленник может подделать заголовок, отправив запрос с тем же заголовком.

Внедрение защиты от CSRF в Petite-Vue

Для интеграции защиты от CSRF в проект, использующий библиотеку Petite-Vue, необходимо учесть, что сама библиотека предоставляет только инструменты для работы с данными и реактивностью, но не включает в себя механизм защиты от CSRF. Поэтому для защиты потребуется реализовать соответствующие меры на сервере и в приложении.

  1. Добавление токена в формы: В шаблонах, где используется Petite-Vue, можно добавить скрытые поля для передачи CSRF-токенов. После этого, при отправке данных через реактивную форму, нужно включать этот токен.

  2. Передача токенов через AJAX: В случае, если данные отправляются через AJAX-запросы, необходимо убедиться, что токен CSRF отправляется в заголовках или теле запроса.

Пример компонента Petite-Vue с добавлением CSRF-токена:

<div x-data="{ formData: { name: '', email: '' }, csrfToken: '{{ csrf_token() }}' }">
  <form @submit.prevent="submitForm">
    <input type="hidden" name="csrf_token" :value="csrfToken">
    <input type="text" x-model="formData.name" placeholder="Your Name">
    <input type="email" x-model="formData.email" placeholder="Your Email">
    <button type="submit">Submit</button>
  </form>

  <script>
    function submitForm() {
      fetch('/submit', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-CSRF-Token': this.csrfToken
        },
        body: JSON.stringify(this.formData)
      }).then(response => response.json())
        .then(data => console.log(data));
    }
  </script>
</div>

Заключение

Защита от CSRF-атак играет ключевую роль в обеспечении безопасности веб-приложений. Использование уникальных токенов, проверка заголовков и правильная настройка cookies — это основные методы, которые помогают избежать этих атак. Важно помнить, что эффективная защита требует комплексного подхода, и каждый метод должен использоваться в зависимости от контекста приложения и его инфраструктуры.