Saya ingin menambahkan otentikasi multi-faktor dengan token lunak TOTP ke aplikasi Angular & Spring, sambil menjaga semuanya sedekat mungkin dengan default dari Spring Boot Security Starter .
Validasi token terjadi secara lokal (dengan pustaka aerogear-otp-java), tidak ada penyedia API pihak ketiga.
Menyiapkan token untuk pengguna berfungsi, tetapi memvalidasinya dengan memanfaatkan Spring Security Authentication Manager / Penyedia tidak.
TL; DR
- Apa cara resmi untuk mengintegrasikan AuthenticationProvider tambahan ke sistem terkonfigurasi Spring Boot Security Starter ?
- Apa cara yang disarankan untuk mencegah serangan replay?
Versi Panjang
API memiliki titik akhir /auth/token
dari mana frontend bisa mendapatkan token JWT dengan memberikan nama pengguna dan kata sandi. Respons juga mencakup status otentikasi, yang dapat berupa AUTHENTICATED atau PRE_AUTHENTICATED_MFA_REQUIRED .
Jika pengguna membutuhkan MFA, token diberikan dengan otoritas tunggal PRE_AUTHENTICATED_MFA_REQUIRED
dan waktu kedaluwarsa 5 menit. Ini memungkinkan pengguna untuk mengakses titik akhir di /auth/mfa-token
mana mereka dapat memberikan kode TOTP dari aplikasi Authenticator mereka dan mendapatkan token yang sepenuhnya dikonfirmasi untuk mengakses situs.
Penyedia dan Token
Saya telah membuat kebiasaan saya MfaAuthenticationProvider
yang mengimplementasikan AuthenticationProvider
:
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// validate the OTP code
}
@Override
public boolean supports(Class<?> authentication) {
return OneTimePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
Dan OneTimePasswordAuthenticationToken
yang meluas AbstractAuthenticationToken
untuk menampung nama pengguna (diambil dari JWT yang ditandatangani) dan kode OTP.
Konfigurasi
Saya memiliki kebiasaan saya WebSecurityConfigurerAdapter
, tempat saya menambahkan kebiasaan saya AuthenticationProvider
melalui http.authenticationProvider()
. Menurut JavaDoc, ini sepertinya tempat yang tepat:
Mengizinkan menambahkan AuthenticationProvider tambahan untuk digunakan
Bagian yang relevan dari SecurityConfig
penampilan saya seperti ini.
@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
Pengendali
The AuthController
telah yang AuthenticationManagerBuilder
disuntikkan dan menariknya semua bersama-sama.
@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
Namun, memposting yang /auth/mfa-token
mengarah pada kesalahan ini:
"error": "Forbidden",
"message": "Access Denied",
"trace": "org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for de.....OneTimePasswordAuthenticationToken
Mengapa Spring Security tidak mengambil Penyedia Autentikasi saya? Debugging controller menunjukkan kepada saya bahwa itu DaoAuthenticationProvider
adalah satu-satunya Penyedia Autentikasi di AuthenticationProviderManager
.
Jika saya mengekspos MfaAuthenticationProvider
kacang saya , itu adalah satu - satunya Penyedia yang terdaftar, jadi saya mendapatkan yang sebaliknya:
No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken.
Jadi, bagaimana saya mendapatkan keduanya?
Pertanyaan saya
Apa cara yang disarankan untuk mengintegrasikan tambahan AuthenticationProvider
ke sistem terkonfigurasi Spring Boot Security Starter , sehingga saya mendapatkan keduanya, DaoAuthenticationProvider
kebiasaan dan kebiasaan saya sendiri MfaAuthenticationProvider
? Saya ingin mempertahankan default Spring Boot Scurity Starter dan memiliki Penyedia sendiri.
Pencegahan Serangan Putar Ulang
Saya tahu bahwa algoritma OTP tidak dengan sendirinya melindungi terhadap serangan replay dalam slice waktu di mana kode tersebut valid; RFC 6238 memperjelas hal ini
Verifier TIDAK HARUS menerima upaya kedua OTP setelah validasi yang berhasil dikeluarkan untuk OTP pertama, yang memastikan hanya sekali pakai OTP.
Saya bertanya-tanya apakah ada cara yang disarankan untuk menerapkan perlindungan. Karena token OTP berbasis waktu, saya berpikir untuk menyimpan login yang berhasil terakhir pada model pengguna dan memastikan hanya ada satu login yang berhasil per 30 detik slice waktu. Ini tentu saja berarti sinkronisasi pada model pengguna. Adakah pendekatan yang lebih baik?
Terima kasih.
-
PS: karena ini pertanyaan tentang keamanan saya mencari jawaban dari sumber yang kredibel dan / atau resmi. Terima kasih.