Question
I am trying to learn Spring Security right now and I have seen many different examples using this. I know what CSRF is and that Spring Security enables it by default. The thing that I am curious about to know is this kind of customization.
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.authorizeRequests(request -> {
request
.antMatchers("/login").permitAll()
.anyRequest()
....more code
What kind of customization does
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
this line and when it is appropriate to use it. I would appreciate it if
anyone can come with a simple explanation.
Answer
CSRF stands for Cross Site Request Forgery
It is one kind of token that is sent with the request to prevent the attacks.
In order to use the Spring Security CSRF protection, we'll first need to make
sure we use the proper HTTP methods for anything that modifies the state
(PATCH
, POST
, PUT
, and DELETE
– not GET
).
CSRF protection with Spring CookieCsrfTokenRepository works as follows:
- The client makes a GET request to Server (Spring Boot Backend), e.g. request for the main page
- Spring sends the response for GET request along with
Set-cookie
header which contains securely generated XSRF Token - The browser sets the cookie with XSRF Token
- While sending a state-changing request (e.g. POST) the client (might be angular) copies the cookie value to the HTTP request header
- The request is sent with both header and cookie (browser attaches the cookie automatically)
- Spring compares the header and the cookie values, if they are the same the request is accepted, otherwise, 403 is returned to the client
The method withHttpOnlyFalse
allows angular to read XSRF cookie. Make sure
that Angular makes XHR request with withCreddentials
flag set to true.
Code from CookieCsrfTokenRepository
@Override
public CsrfToken generateToken(HttpServletRequest request) {
return new DefaultCsrfToken(this.headerName, this.parameterName,
createNewToken());
}
@Override
public void saveToken(CsrfToken token, HttpServletRequest request,
HttpServletResponse response) {
String tokenValue = token == null ? "" : token.getToken();
Cookie cookie = new Cookie(this.cookieName, tokenValue);
cookie.setSecure(request.isSecure());
if (this.cookiePath != null && !this.cookiePath.isEmpty()) {
cookie.setPath(this.cookiePath);
} else {
cookie.setPath(this.getRequestContext(request));
}
if (token == null) {
cookie.setMaxAge(0);
}
else {
cookie.setMaxAge(-1);
}
cookie.setHttpOnly(cookieHttpOnly);
if (this.cookieDomain != null && !this.cookieDomain.isEmpty()) {
cookie.setDomain(this.cookieDomain);
}
response.addCookie(cookie);
}
@Override
public CsrfToken loadToken(HttpServletRequest request) {
Cookie cookie = WebUtils.getCookie(request, this.cookieName);
if (cookie == null) {
return null;
}
String token = cookie.getValue();
if (!StringUtils.hasLength(token)) {
return null;
}
return new DefaultCsrfToken(this.headerName, this.parameterName, token);
}
public static CookieCsrfTokenRepository withHttpOnlyFalse() {
CookieCsrfTokenRepository result = new CookieCsrfTokenRepository();
result.setCookieHttpOnly(false);
return result;
}
You may explore the methods [here](https://docs.spring.io/spring- security/site/docs/4.2.15.RELEASE/apidocs/org/springframework/security/web/csrf/CookieCsrfTokenRepository.html)