Я прочитал документы и все связанные вопросы по SO, но все же механизм XSRF в Angular у меня не работает: я никоим образом не могу сделать POST-запрос с автоматически добавленным заголовком X-XSRF-TOKEN.
У меня есть приложение Angular 6 с формой входа.
Это часть веб-сайта Symfony (PHP 7.1), а страница приложения Angular, когда обслуживается из Symfony, отправляет правильный файл cookie (XSRF-TOKEN):
Мой 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. Почему?
Спасибо, подумал, но решил проблему более аккуратно: пожалуйста, посмотрите мой ответ.
Привет, Стефан, не могли бы вы помочь мне сгенерировать значение токена XSRF в угловой версии 6 с PHP в качестве моего бэкэнда, я не смог выполнить var_dump токена XSRF, потому что, поскольку я не могу сгенерировать токен в typeScript Кликните сюда, я опубликовал это проблема!
@Nishanth ॐ пожалуйста, взгляните на свой вопрос, я добавил ответ с образцом кода.





Убедитесь, что ваш сервер разрешает использование заголовков X-CSRF-Token, когда браузер запрашивает метод OPTIONS.
Пример:
Access-Control-Allow-Headers: X-CSRF-Token, Content-Type
Ссылка: Документы MDN
Проблема снова в плохой документации Angular.
Дело в том, что Angular добавит заголовок X-XSRF-TOKENтолько если, файл cookie XSRF-TOKEN был сгенерирован на стороне сервера со следующими параметрами:
/false (это очень важно, и полностью недокументированный)Кроме того, приложение Angular и вызываемый URL-адрес должны находиться на одном сервере.
Ссылка: эта проблема Angular Github
В дополнение к вышесказанному: - Заголовок НЕ установлен для запросов GET или HEAD - Имя файла cookie должно быть: XSRF-TOKEN (если имя по умолчанию не переопределено) - Самое важное, убедитесь, что вы не используете абсолютные пути. Под этим подразумеваются пути, начинающиеся с HTTP или HTTPS. Это ДОЛЖЕН быть ОТНОСИТЕЛЬНЫЙ путь.
Означает ли это, что все запросы на стороне моего сервера должны поступать из домена моего сайта, а не с выделенного URL-адреса API? пример: localhost: 4000 / home - это SPA, а мой apis будет на localhost: 4000 / api / getSomething вместо localhost: 8080 / api / getSomething
@Anthony cookie устанавливается со страницы на стороне сервера и считывается из SPA, поэтому и SPA, и api должны быть как минимум на одном и том же 2-м уровне домен, чтобы cookie можно было прочитать из SPA. Это могло бы сработать, если бы сервер и SPA работали на разных порты одного и того же домена, как в вашем примере, но я не тестировал этот сценарий.
@Merv Итак, почему GET не защищен от XSRF? Я новичок в понимании XSRF и, возможно, еще не понимаю его полностью, но кажется, что злоумышленник может «ПОЛУЧИТЬ» данные, которые они не должны иметь. Не могли бы вы прояснить это для меня?
@RuneStar Это правда, но по этой причине вы никогда не должны предоставлять изменяющие запросы в методе GET. GET является особенным, потому что очень легко обмануть пользователя, заставив его выполнить запрос GET, отобразив «изображение», URL-адрес которого является чем-то неприятным, например <img src = "/backend/drop-database">.
@ArnaudDenoyelle Спасибо. Я понимаю, что вы не хотите мутировать в GET, потому что он не предназначен для этого и, как вы подразумевали, может привести к уязвимости, если это произойдет. Но мне интересно, может ли злоумышленник получить данные, возвращаемые GET? Будет ли он возвращен исходному пользователю или он будет возвращен в «межсайтовом запросе» злоумышленников?
Защита @RuneStar XSRF не предназначена для защиты веб-приложения от несанкционированного доступа, то есть злоумышленников, которые получают данные с помощью запросов GET. Защита XSRF предназначена для защиты ваших официальных пользователей вашего веб-приложения от злонамеренных пользователей, которые могут изменять / изменять данные в вашем веб-приложении от имени ваших официальных пользователей. И как сказал Арно. Запрос на получение никогда не должен использоваться для изменения данных. Только для получения данных. Если вы хотите защитить приложение ur от получения данных от злонамеренных пользователей, вам следует изучить защиту URL-адресов ur от общественности с различными привилегиями ролей. PM для получения дополнительной информации.
@Merv Скажем, злоумышленник каким-то образом заставляет жертву получить доступ к своему вредоносному веб-сайту после того, как пользователь вошел в мое приложение. Этот вредоносный сайт имеет примерно следующее: <form id = "csrf-form" method = 'GET' action = 'https: // myApp / api / getSensitiveData'>. Возможно ли, чтобы возвращенные данные были отправлены злоумышленнику? Обратите внимание, я проверяю аутентификацию / авторизацию.
@RuneStar Нет, это невозможно (только с CSRF). Потому что все происходит на машине пользователя. Таким образом, даже если пользователя обманывают, ответ (с конфиденциальными данными) достигает компьютера пользователя, так что злоумышленник ничего от этого не получает. Единственный способ получить что-то злоумышленник - это сделать (выполнить / изменить / отредактировать) что-то от имени пользователя, что принесет ему пользу. Например, с помощью онлайн-банкинга для отправки денег на его счет. И пользователь увидит сообщение (если банк покажет сообщение о том, что деньги были отправлены) .... $ был отправлен на «злонамеренную учетную запись пользователя». Надеюсь, вы поняли!
@PaoloStefan, что подразумевается под Path = /. И как его установить, если у нас есть Spring boot backend.
Слегка не по теме, но для других, кто приходит сюда, я решил эту проблему в задней части следующим образом (для 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».
Ни одно другое решение у нас не сработало.
Пока это единственное решение, которое у меня сработало. Но я не понимаю почему.
Из-за это
Вы должны поставить сервис на фронтенд этот { 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. Теперь это имеет смысл.
Да, это работает. Не может быть http://..., потому что он не устанавливает заголовок и не может быть установлен без двойных косых черт, по крайней мере, не во время ng serve, потому что я получаю ошибку CORS (мой файл environment.ts имеет базовый URL-адрес API //example.test + номер порта, чтобы HTTP-запросы можно было протестировать на ng serve и после сборки на моем локальном компьютере)
request = request.clone({
withCredentials: true
});
В InterceptService это работает со мной
Думаю, вы могли бы написать свой собственный перехватчик, чтобы справиться с этим. Я знаю, что у некоторых пользователей были проблемы с этим, когда не использовать абсолютные URL