Spring Boot 2 ve Spring Security 5 ile Çok Faktörlü Kimlik Doğrulama


11

Her şeyi Spring Boot Security Starter'ın varsayılan ayarlarına olabildiğince yakın tutarken, bir Açısal ve Yay uygulamasına TOTP yumuşak belirteçleriyle çok faktörlü kimlik doğrulama eklemek istiyorum .

Belirteç doğrulaması, üçüncü taraf API sağlayıcısı olmayan yerel olarak (aerogear-otp-java kitaplığıyla) gerçekleşir.

Bir kullanıcı için belirteçler ayarlamak çalışır, ancak Spring Security Authentication Manager / Providers'dan yararlanarak bunları doğrulamak işe yaramaz.

TL; DR

  • Ek bir AuthenticationProvider'ı Spring Boot Security Starter yapılandırılmış bir sisteme entegre etmenin resmi yolu nedir ?
  • Tekrar saldırılarını önlemenin önerilen yolları nelerdir?

Uzun versiyon

API, /auth/tokenkullanıcı arabirimi ve şifre sağlayarak ön ucun bir JWT jetonu alabileceği bir uç noktaya sahiptir . Yanıt ayrıca AUTHENTICATED veya PRE_AUTHENTICATED_MFA_REQUIRED olabilen bir kimlik doğrulama durumu da içerir .

Kullanıcı MFA gerektiriyorsa, jetona tek bir yetki PRE_AUTHENTICATED_MFA_REQUIREDve 5 dakikalık bir sona erme süresi verilir . Bu, kullanıcının /auth/mfa-tokenKimlik Doğrulayıcı uygulamasından TOTP kodunu sağlayabileceği uç noktaya erişmesine ve siteye erişmek için tamamen doğrulanmış jetonu almasına olanak tanır .

Sağlayıcı ve Jeton

MfaAuthenticationProviderUygulamamı oluşturdum AuthenticationProvider:

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        // validate the OTP code
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return OneTimePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }

Ve bir kullanıcı adı (imzalı JWT'den alınmıştır) ve OTP kodunu tutmaya OneTimePasswordAuthenticationTokenuzanır AbstractAuthenticationToken.

Yapılandırma

Benim özel var WebSecurityConfigurerAdapterbenim özel eklemek, AuthenticationProviderüzeri http.authenticationProvider(). JavaDoc'a göre, bu doğru yer gibi görünüyor:

Kullanılacak ek bir AuthenticationProvider eklemeye izin verir

Benim ilgili kısımlarım SecurityConfigböyle görünüyor.

    @Configuration
    @EnableWebSecurity
    @EnableJpaAuditing(auditorAwareRef = "appSecurityAuditorAware")
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
        private final TokenProvider tokenProvider;

        public SecurityConfig(TokenProvider tokenProvider) {
            this.tokenProvider = tokenProvider;
        }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authenticationProvider(new MfaAuthenticationProvider());

        http.authorizeRequests()
            // Public endpoints, HTML, Assets, Error Pages and Login
            .antMatchers("/", "favicon.ico", "/asset/**", "/pages/**", "/api/auth/token").permitAll()

            // MFA auth endpoint
            .antMatchers("/api/auth/mfa-token").hasAuthority(ROLE_PRE_AUTH_MFA_REQUIRED)

            // much more config

kontrolör

AuthControllerOlan AuthenticationManagerBuilderenjekte edilir ve hep birlikte çekme edilir.

@RestController
@RequestMapping(AUTH)
public class AuthController {
    private final TokenProvider tokenProvider;
    private final AuthenticationManagerBuilder authenticationManagerBuilder;

    public AuthController(TokenProvider tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder) {
        this.tokenProvider = tokenProvider;
        this.authenticationManagerBuilder = authenticationManagerBuilder;
    }

    @PostMapping("/mfa-token")
    public ResponseEntity<Token> mfaToken(@Valid @RequestBody OneTimePassword oneTimePassword) {
        var username = SecurityUtils.getCurrentUserLogin().orElse("");
        var authenticationToken = new OneTimePasswordAuthenticationToken(username, oneTimePassword.getCode());
        var authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);

        // rest of class

Ancak, karşı /auth/mfa-tokengönderilmek şu hataya yol açar:

"error": "Forbidden",
"message": "Access Denied",
"trace": "org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for de.....OneTimePasswordAuthenticationToken

Spring Security neden Kimlik Doğrulama Sağlayıcımı almıyor? Denetleyicinin hata ayıklaması bana bunun DaoAuthenticationProvideriçindeki Tek Kimlik Doğrulama Sağlayıcısı olduğunu gösteriyor AuthenticationProviderManager.

Eğer benim MfaAuthenticationProviderfasulye olarak ifşa , kayıtlı tek Sağlayıcı olduğunu, bu yüzden tam tersi olsun:

No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken. 

Peki, ikisini nasıl edinebilirim?

Benim sorum

AuthenticationProviderBir eklentiyi Spring Boot Security Starter yapılandırmalı sisteme entegre etmenin önerilen yolu nedir , böylece hem DaoAuthenticationProviderbenim hem de kendi özelim olsun MfaAuthenticationProvider? Spring Boot Scurity Starter'ın varsayılan değerlerini korumak ve ek olarak kendi Sağlayıcımı kullanmak istiyorum.

Tekrar Saldırının Önlenmesi

OTP algoritmasının kodun geçerli olduğu zaman dilimi içinde tekrar saldırılarına karşı koruma sağlamadığını biliyorum; RFC 6238 bunu açıkça ortaya koyuyor

Doğrulayıcı, ilk OTP için başarılı doğrulama yapıldıktan sonra OTP'nin ikinci denemesini kabul ETMEMELİDİR ZORUNLU, bu sadece OTP'nin tek seferlik kullanılmasını sağlar.

Korumayı uygulamak için önerilen bir yol olup olmadığını merak ediyordum. OTP jetonları zamana dayalı olduğundan, son başarılı girişi kullanıcının modelinde saklamayı ve 30 saniyelik zaman diliminde sadece bir başarılı giriş olduğundan emin olmayı düşünüyorum. Bu elbette kullanıcı modelinde senkronizasyon anlamına gelir. Daha iyi yaklaşımlar var mı?

Teşekkür ederim.

-

Not: Bu güvenlikle ilgili bir soru olduğundan, güvenilir ve / veya resmi kaynaklardan bir cevap çizimi arıyorum. Teşekkür ederim.

Yanıtlar:


0

Kendi sorumu cevaplamak için, daha fazla araştırmadan sonra bunu nasıl uyguladım.

Ben bir pojo olarak uygulayan bir sağlayıcı var AuthenticationProvider. Kasıtlı olarak bir Fasulye / Bileşen değil. Aksi takdirde, Spring bunu tek Sağlayıcı olarak kaydederdi.

public class MfaAuthenticationProvider implements AuthenticationProvider {
    private final AccountService accountService;

    @Override
    public Authentication authenticate(Authentication authentication) {
        // here be code 
        }

SecurityConfig'imde, Spring'in otomatik olarak bağlanmasına izin verdim AuthenticationManagerBuilderveMfaAuthenticationProvider

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
       private final AuthenticationManagerBuilder authenticationManagerBuilder;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // other code  
        authenticationManagerBuilder.authenticationProvider(getMfaAuthenticationProvider());
        // more code
}

// package private for testing purposes. 
MfaAuthenticationProvider getMfaAuthenticationProvider() {
    return new MfaAuthenticationProvider(accountService);
}

Standart kimlik doğrulamasından sonra, kullanıcının MFA etkinleştirilmişse, önceden PRE_AUTHENTICATED_MFA_REQUIRED yetkisi verilen bir kimlik doğrulaması yapılır . Bu, tek bir uç noktaya erişmelerini sağlar /auth/mfa-token. Bu uç nokta, kullanıcı adını geçerli JWT'den ve sağlanan TOTP'den alır ve bunu, işleyebileceği şekilde authenticate()seçen authenticationManagerBuilder yöntemine gönderir .MfaAuthenticationProviderOneTimePasswordAuthenticationToken

    var authenticationToken = new OneTimePasswordAuthenticationToken(usernameFromJwt, providedOtp);
    var authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.