XSRF - как установить кросс-источник cookie
Я разработал REST API и два клиента JavaScript (одностраничное приложение и нативное приложение - на основе электроники). В обоих клиентах мои пользователи проходят аутентификацию через поток OAuth2:
- отправляет пароль пользователя на сервер
- получает access_token (в виде простого текста) и refresh_token (в файле cookie httponly)
- по истечении срока действия токена они обновляют его, отправляя запрос в конечную точку /refresh (сервер считывает refresh_token из cookie-файла)
Теперь я хотел бы реализовать защиту CSRF. Так что я реализовал это на моей стороне (Spring):
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and()
.authorizeRequests().antMatchers("/", "/index.html", "/token/**").permitAll()
.anyRequest().authenticated();
}
Мой SPA работает отлично, angular читает XSRF-TOKEN из cookie и отправляет его в заголовке X-XSRF-TOKEN. У меня проблема с электронным приложением. У него нет доступа к cookie (из-за разного происхождения - электрон работает на file://
url), поэтому невозможно установить заголовок X-XSRF-TOKEN.
Как я могу справиться с такой проблемой? Есть ли какой-нибудь способ создать "перекрестное" печенье? Или, может быть, я могу каким-то образом получить значение cookie через API API для электронной магии электронов (если у него есть доступ к файловой системе, возможно, у него есть доступ к любому cookie, созданному на машине)?
0 ответов
У меня была та же проблема, и в конце концов мне удалось ее исправить, реализовав угловой перехватчик http, например:
@Injectable()
export class HttpXsrfInterceptor implements HttpInterceptor {
constructor(private tokenExtractor: HttpXsrfTokenExtractor, //from angular
private nativeAuthService: NativeAuthService) { //my native service
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
//this works in web
const headerName = 'X-XSRF-TOKEN';
const token = this.tokenExtractor.getToken() as string;
if (token !== null && !req.headers.has(headerName)) {
req = req.clone({ headers: req.headers.set(headerName, token) });
return next.handle(req);
}
//this works in electron
return this.nativeAuthService.getCookieValue('XSRF-TOKEN').pipe(
mergeMap((xsrfToken: string) => {
if (xsrfToken && !req.headers.has(headerName)) {
req = req.clone({ headers: req.headers.set(headerName, xsrfToken) });
}
return next.handle(req);
}),
);
}
}
А мой nativeAuthService просто вызывает этот метод в основном процессе электрона:
export function getCookieValue(cookieName: string): Observable<string> {
return from(session.defaultSession.cookies.get({ name: cookieName })
.then((cookies: Electron.Cookie[]) => {
if (cookies.length == 1) {
return cookies[0].value;
} else {
if (cookies.length > 1) {
throw Error(`There is more than one cookie with the name: ${ cookieName }.`);
}
return '';
}
}));
}