13 Şubat 2020 Perşembe

SpringSecurity HttpSessionCsrfTokenRepository Sınıfı - Http Session'da CSRF Token İçin Kullanılacak Parametre İsimlerini Belirtir

Giriş
Açıklaması şöyle. CSRF yazısına bakabilirsiniz. 
Kullanıcı giriş yapınca bir tane CSRF Token üretilir ve gönderilir. Bu token sunucudaki HttpSession içinde saklanır. Kullanıcının her Http isteğinde bu token'ı da göndermelidir, yoksa istek reddedilir. Yani tüm session boyunca kullanılacak CSRF Token'ı saklar.
Persist the CSRF token in the HttpSession in the parameter with the name set by calling method setParameterName() and reads from the header with the name set by calling the setHeaderName()
X-CSRF-TOKEN Nedir?
Açıklaması şöyle.
When a user visits a web application protected by CSRF, HttpSessionCsrfTokenRepository generates a CSRF token and stores it in the user's HTTP session. The token is associated with the user's session on the server side and is not accessible to the client-side JavaScript. The generated token is typically sent to the client in a response header (e.g., X-CSRF-TOKEN) or embedded in a form as a hidden input field.

On subsequent requests from the user, the HttpSessionCsrfTokenRepository retrieves the CSRF token from the user's HTTP session and validates it against the token received in the request (either from the header or the form field). If the tokens match, the request is considered valid, and the server processes it. If the tokens don't match or are missing, the server can reject the request as a potential CSRF attack.
Bu sınıf org.springframework.security.web.csrf.CsrfFilter tarafından kullanılır.

X-XSRF-TOKEN Nedir
Açıklaması şöyle
- It is added to request header for ajax requests.
- Popular libraries like angular and axios, automatically get value of this header from xsrf-token cookie and send it with every request.
Bir başka açıklama şöyle.
For every request that your Angular application makes of your server, the Angular $http service will do these things automatically:

Look for a cookie named XSRF-TOKEN on the current domain.
If that cookie is found, it reads the value and adds it to the request as the X-XSRF-TOKEN header
Thymeleaf ise _csrf.parameterName olarak erişir

generateToken metodu
Örnek
Elimizde şöyle bir kod olsun
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;

public class PerRequestCsrfTokenRepository implements CsrfTokenRepository {
  private static final String DEFAULT_CSRF_HEADER_NAME = "X-CSRF-TOKEN";
  private static final String DEFAULT_CSRF_PARAMETER_NAME = "_csrf";

  @Override
  public CsrfToken generateToken(HttpServletRequest request) {
    return new DefaultCsrfToken(DEFAULT_CSRF_HEADER_NAME, DEFAULT_CSRF_PARAMETER_NAME, 
      createNewToken());
  }

  @Override
  public void saveToken(CsrfToken token, HttpServletRequest request, 
    HttpServletResponse response) {
    // No need to save the token since a new one will be created for every request
  }

  @Override
  public CsrfToken loadToken(HttpServletRequest request) {
    // Always return null so that a new token is created for every request
    return null;
  }

  private String createNewToken() {
    // Your logic for creating a new CSRF token here
    return new String(Base64.getUrlEncoder().withoutPadding()
      .encode(UUID.randomUUID().toString().getBytes()));
  }
}
Kullanmak için şöyle yaparız
@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .csrf()
            .csrfTokenRepository(new PerRequestCsrfTokenRepository())
        .and()
        .authorizeRequests()
        .anyRequest().authenticated()
        .and()
        .formLogin().permitAll();
}

setHeaderName metodu
Örnek
Elimizde şöyle bir kod olsun.
private CsrfTokenRepository csrfTokenRepository() {
  HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
  repository.setHeaderName("X-XSRF-TOKEN");
  return repository;
}
Şöyle yaparız.
http.csrf()
  .csrfTokenRepository(csrfTokenRepository())
  ...
Örnek
Şöyle yaparız
@Configuration
@EnableWebSecurity
public class SecurityConfig {

  @Bean
  public CsrfTokenRepository csrfTokenRepository() {
    HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
    repository.setHeaderName("X-XSRF-TOKEN");
    return repository;
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests()
        .antMatchers("/example/form").permitAll()
        .anyRequest().authenticated()
      .and()
        .formLogin()
      .and()
        .csrf()
          .csrfTokenRepository(csrfTokenRepository());
    }
}

Örnek
Şöyle yaparız.
private CsrfTokenRepository csrfTokenRepository() {
  HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
    repository.setHeaderName("X-XSRF-TOKEN");
  return repository;
}
setParameterName metodu
Şöyle yaparız
@Bean
public CsrfTokenRepository repo() {
  HttpSessionCsrfTokenRepository repo = new HttpSessionCsrfTokenRepository();
  repo.setParameterName("_csrf");
  repo.setHeaderName("X-CSRF-TOKEN");
  return repo;
}

Hiç yorum yok:

Yorum Gönder