Какие HTTP-методы считаются безопасными (safe) и почему это важно для тестирования?

«Какие HTTP-методы считаются безопасными (safe) и почему это важно для тестирования?» — вопрос из категории Тестирование безопасности, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Согласно спецификации HTTP, безопасными (safe) считаются методы, которые не должны изменять состояние сервера. Они предназначены только для получения данных. К ним относятся:

  • GET — для получения ресурса.
  • HEAD — аналогичен GET, но сервер возвращает только заголовки ответа без тела.
  • OPTIONS — для получения поддерживаемых методов для ресурса.
  • TRACE — для диагностики (используется редко).

Важность для тестирования безопасности и корректности API:

  1. Идемпотентность и побочные эффекты: В тестах я всегда проверяю, что безопасные методы действительно не вносят изменений. Например, многократный вызов GET /api/users не должен создавать новых пользователей, списывать средства или блокировать аккаунты. Это проверяется сравнением состояния системы до и после серии запросов.

  2. Кэширование: Безопасные методы, в частности GET, по умолчанию подлежат кэшированию. При тестировании я проверяю, что API возвращает корректные заголовки кэширования (Cache-Control, ETag), и что кэшированные данные не приводят к отображению устаревшей или конфиденциальной информации другого пользователя.

  3. Безопасность: С точки зрения безопасности, GET-запросы не должны использоваться для операций, меняющих состояние, так как их параметры остаются в истории браузера, логах и могут передаваться по ссылке. В тестах я специально пытаюсь отправить данные, которые должны передаваться через POST (например, credentials), методом GET и ожидаю, что сервер отклонит такой запрос или будет обрабатывать его безопасно.

Пример теста, проверяющего безопасность GET-запроса:

@Test
public void get_request_should_not_create_resource() {
    // Запоминаем начальное состояние
    int initialUserCount = userService.getAllUsers().size();

    // Пытаемся выполнить GET с параметрами, похожими на создание
    Response response = given()
                            .queryParam("name", "Hacker")
                            .queryParam("email", "hack@test.com")
                         .when()
                            .get("/api/users"); // НЕПРАВИЛЬНЫЙ дизайн API, если так можно создать

    // Проверяем, что запрос завершился успешно (для получения данных), но НЕ создал сущность
    assertThat(response.statusCode()).isEqualTo(200);
    assertThat(userService.getAllUsers().size())
        .as("GET request should not change state")
        .isEqualTo(initialUserCount);
}

Понимание семантики безопасных методов — основа для проектирования корректных REST API и написания точных тестов на их безопасность и надёжность.