问题
I have UI written with Angular 2 and Java based backend that uses OpenID Connect authentication on top of Spring Security.
The authentication works fine but only for GET requests. I'm getting HTTP 403 every time I perform POST, PUT or DELETE methods on a resource:
{
"status": 403,
"message": "Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-CSRF-TOKEN'.",
}
I use HttpClient like this:
http.post(
'/api/my-resource',
JSON.stringify(myObject),
new RequestOptions({
headers: new Headers({'Content-Type': 'application/json'})
})
)
When I add withCredentials: true
to the RequestOptions as proposed here I still get HTTP 403 but with different message:
{
"status": 403,
"message": "Could not verify the provided CSRF token because your session was not found.",
}
What do I need to do to make HttpClient
work with CSRF?
Note: I also took a look at similar questions, especially angular-2-spring-security-csrf-implementation-problems, but the solutions proposed there do not solve my problem. At the same time I don't want to disable CSRF.
回答1:
Update Angular >= 6
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule,
HttpClientXsrfModule.withOptions({cookieName: 'XSRF-TOKEN'})
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
}
Original answer
Add the CSRF
cookie configuration as below :
@NgModule({
declarations: [declarations],
imports: [imports],
providers:
[
{provide: XSRFStrategy, useFactory: xsrfFactory}
],
bootstrap: [AppComponent]
})
export class AppModule {
}
export function xsrfFactory() {
return new CookieXSRFStrategy('XSRF-TOKEN', 'XSRF-TOKEN');
}
And configure Spring security with the correct header name.
private static final String CSRF_HEADER_NAME = "XSRF-TOKEN";
@Override
protected void configure(HttpSecurity http) throws Exception {
http
...
.and()
.csrf()
.ignoringAntMatchers(CSRF_IGNORE)
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName(CSRF_HEADER_NAME);
return repository;
}
where CsrfHeaderFilter :
public class CsrfHeaderFilter extends OncePerRequestFilter {
private static final String CSRF_COOKIE_NAME = "XSRF-TOKEN";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, CSRF_COOKIE_NAME);
String token = csrf.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie(CSRF_COOKIE_NAME, token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
}
来源:https://stackoverflow.com/questions/45237003/csrf-issue-while-sending-post-request-from-angular-2-to-spring-backed-java-app