Angular 6 не добавляет заголовок X-XSRF-TOKEN в HTTP-запрос

Я прочитал документы и все связанные вопросы по SO, но все же механизм XSRF в Angular у меня не работает: я никоим образом не могу сделать POST-запрос с автоматически добавленным заголовком X-XSRF-TOKEN.

У меня есть приложение Angular 6 с формой входа.

Это часть веб-сайта Symfony (PHP 7.1), а страница приложения Angular, когда обслуживается из Symfony, отправляет правильный файл cookie (XSRF-TOKEN):

Angular 6 не добавляет заголовок X-XSRF-TOKEN в HTTP-запрос

Мой app.module.ts включает в себя правильные модули:

// other imports...
import {HttpClientModule, HttpClientXsrfModule} from "@angular/common/http";

// ...
@NgModule({
  declarations: [
    // ...
  ],
  imports: [
    NgbModule.forRoot(),
    BrowserModule,
    // ...
    HttpClientModule,
    HttpClientXsrfModule.withOptions({
      cookieName: 'XSRF-TOKEN',
      headerName: 'X-CSRF-TOKEN'
    }),
    // other imports
  ],
  providers: [],
  entryComponents: [WarningDialog],
  bootstrap: [AppComponent]
})
export class AppModule {
}

Затем внутри метода службы я делаю следующий HTTP-запрос (this.http является экземпляром HttpClient):

this.http
    .post<any>('api/login', {'_username': username, '_pass': password})
    .subscribe(/* handler here */);

Почтовый запрос никогда не отправляет заголовок X-XSRF-TOKEN. Почему?

Думаю, вы могли бы написать свой собственный перехватчик, чтобы справиться с этим. Я знаю, что у некоторых пользователей были проблемы с этим, когда не использовать абсолютные URL

Michael Doye 24.05.2018 16:15

Спасибо, подумал, но решил проблему более аккуратно: пожалуйста, посмотрите мой ответ.

Paolo Stefan 24.05.2018 16:19

Привет, Стефан, не могли бы вы помочь мне сгенерировать значение токена XSRF в угловой версии 6 с PHP в качестве моего бэкэнда, я не смог выполнить var_dump токена XSRF, потому что, поскольку я не могу сгенерировать токен в typeScript Кликните сюда, я опубликовал это проблема!

Nɪsʜᴀɴᴛʜ ॐ 18.09.2018 12:10

@Nishanth ॐ пожалуйста, взгляните на свой вопрос, я добавил ответ с образцом кода.

Paolo Stefan 18.09.2018 12:36
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
31
4
37 354
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Убедитесь, что ваш сервер разрешает использование заголовков X-CSRF-Token, когда браузер запрашивает метод OPTIONS.

Пример:

Access-Control-Allow-Headers: X-CSRF-Token, Content-Type

Ссылка: Документы MDN

Ответ принят как подходящий

Проблема снова в плохой документации Angular.

Дело в том, что Angular добавит заголовок X-XSRF-TOKENтолько если, файл cookie XSRF-TOKEN был сгенерирован на стороне сервера со следующими параметрами:

  • Путь = /
  • httpOnly = false (это очень важно, и полностью недокументированный)

Кроме того, приложение Angular и вызываемый URL-адрес должны находиться на одном сервере.

Ссылка: эта проблема Angular Github

В дополнение к вышесказанному: - Заголовок НЕ установлен для запросов GET или HEAD - Имя файла cookie должно быть: XSRF-TOKEN (если имя по умолчанию не переопределено) - Самое важное, убедитесь, что вы не используете абсолютные пути. Под этим подразумеваются пути, начинающиеся с HTTP или HTTPS. Это ДОЛЖЕН быть ОТНОСИТЕЛЬНЫЙ путь.

Merv 19.10.2018 16:32

Означает ли это, что все запросы на стороне моего сервера должны поступать из домена моего сайта, а не с выделенного URL-адреса API? пример: localhost: 4000 / home - это SPA, а мой apis будет на localhost: 4000 / api / getSomething вместо localhost: 8080 / api / getSomething

Anthony 06.11.2018 22:49

@Anthony cookie устанавливается со страницы на стороне сервера и считывается из SPA, поэтому и SPA, и api должны быть как минимум на одном и том же 2-м уровне домен, чтобы cookie можно было прочитать из SPA. Это могло бы сработать, если бы сервер и SPA работали на разных порты одного и того же домена, как в вашем примере, но я не тестировал этот сценарий.

Paolo Stefan 07.11.2018 12:15

@Merv Итак, почему GET не защищен от XSRF? Я новичок в понимании XSRF и, возможно, еще не понимаю его полностью, но кажется, что злоумышленник может «ПОЛУЧИТЬ» данные, которые они не должны иметь. Не могли бы вы прояснить это для меня?

Evan Sevy 27.09.2019 17:48

@RuneStar Это правда, но по этой причине вы никогда не должны предоставлять изменяющие запросы в методе GET. GET является особенным, потому что очень легко обмануть пользователя, заставив его выполнить запрос GET, отобразив «изображение», URL-адрес которого является чем-то неприятным, например <img src = "/backend/drop-database">.

Arnaud Denoyelle 27.09.2019 17:55

@ArnaudDenoyelle Спасибо. Я понимаю, что вы не хотите мутировать в GET, потому что он не предназначен для этого и, как вы подразумевали, может привести к уязвимости, если это произойдет. Но мне интересно, может ли злоумышленник получить данные, возвращаемые GET? Будет ли он возвращен исходному пользователю или он будет возвращен в «межсайтовом запросе» злоумышленников?

Evan Sevy 27.09.2019 18:09

Защита @RuneStar XSRF не предназначена для защиты веб-приложения от несанкционированного доступа, то есть злоумышленников, которые получают данные с помощью запросов GET. Защита XSRF предназначена для защиты ваших официальных пользователей вашего веб-приложения от злонамеренных пользователей, которые могут изменять / изменять данные в вашем веб-приложении от имени ваших официальных пользователей. И как сказал Арно. Запрос на получение никогда не должен использоваться для изменения данных. Только для получения данных. Если вы хотите защитить приложение ur от получения данных от злонамеренных пользователей, вам следует изучить защиту URL-адресов ur от общественности с различными привилегиями ролей. PM для получения дополнительной информации.

Merv 27.09.2019 18:47

@Merv Скажем, злоумышленник каким-то образом заставляет жертву получить доступ к своему вредоносному веб-сайту после того, как пользователь вошел в мое приложение. Этот вредоносный сайт имеет примерно следующее: <form id = "csrf-form" method = 'GET' action = 'https: // myApp / api / getSensitiveData'>. Возможно ли, чтобы возвращенные данные были отправлены злоумышленнику? Обратите внимание, я проверяю аутентификацию / авторизацию.

Evan Sevy 27.09.2019 19:45

@RuneStar Нет, это невозможно (только с CSRF). Потому что все происходит на машине пользователя. Таким образом, даже если пользователя обманывают, ответ (с конфиденциальными данными) достигает компьютера пользователя, так что злоумышленник ничего от этого не получает. Единственный способ получить что-то злоумышленник - это сделать (выполнить / изменить / отредактировать) что-то от имени пользователя, что принесет ему пользу. Например, с помощью онлайн-банкинга для отправки денег на его счет. И пользователь увидит сообщение (если банк покажет сообщение о том, что деньги были отправлены) .... $ был отправлен на «злонамеренную учетную запись пользователя». Надеюсь, вы поняли!

Merv 28.09.2019 01:52

@PaoloStefan, что подразумевается под Path = /. И как его установить, если у нас есть Spring boot backend.

Jawadh Salih Rifath 22.11.2019 13:03

Слегка не по теме, но для других, кто приходит сюда, я решил эту проблему в задней части следующим образом (для spring-boot)

     /**
     * CORS config - used by cors() in configure() DO NOT CHANGE the METDHO NAME
     * 
     * @return
     */
    @Bean()
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Lists.newArrayList("http://localhost:4200"));
        configuration.setAllowedMethods(Lists.newArrayList("GET", "POST", "OPTIONS"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(Lists.newArrayList("x-xsrf-token", "XSRF-TOKEN"));
        configuration.setMaxAge(10l);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

После бесчисленных часов борьбы, решение, которое сработало для нас, заключалось в изменении запроса (в Angular) с «https://example.com» на «//example.com».

Ни одно другое решение у нас не сработало.

Пока это единственное решение, которое у меня сработало. Но я не понимаю почему.

Jason Powell 14.12.2019 08:14

Из-за это

yktoo 03.06.2021 21:15

Вы должны поставить сервис на фронтенд этот { withCredentials: true }

Бывший:

this.http.put<class>(url, body, { withCredentials: true });

В моей команде проблема заключалась в том, что мы использовали абсолютный путь вместо относительного.

Итак, не используйте абсолютный путь вроде:

this.http.post<any>("https://example.com/api/endpoint",data)

Использовать

this.http.post<any>("api/endpoint",data)

Или используйте

this.http.post<any>("//example.com/api/endpoint",data)

Это связано с тем, что абсолютные пути явно игнорируются кодом Angular в HttpClientXsrfModule (видеть)

Спасибо за ссылку на код Angular. Теперь это имеет смысл.

Gloire 11.04.2020 13:55

Да, это работает. Не может быть http://..., потому что он не устанавливает заголовок и не может быть установлен без двойных косых черт, по крайней мере, не во время ng serve, потому что я получаю ошибку CORS (мой файл environment.ts имеет базовый URL-адрес API //example.test + номер порта, чтобы HTTP-запросы можно было протестировать на ng serve и после сборки на моем локальном компьютере)

OzzyTheGiant 08.04.2021 17:38
    request = request.clone({
        withCredentials: true
      });

В InterceptService это работает со мной

Другие вопросы по теме