Tôi muốn thêm xác thực đa yếu tố với mã thông báo mềm TOTP vào ứng dụng Angular & Spring, đồng thời giữ mọi thứ gần nhất có thể với các mặc định của Spring Boot Security Starter .
Quá trình xác thực mã thông báo xảy ra cục bộ (với thư viện aerogear-otp-java), không có nhà cung cấp API bên thứ ba.
Thiết lập mã thông báo cho người dùng hoạt động, nhưng xác thực chúng bằng cách tận dụng Trình quản lý / nhà cung cấp xác thực bảo mật Spring thì không.
TL; DR
- Cách chính thức để tích hợp một Trình xác thực bổ sung vào hệ thống được cấu hình Spring Boot Security Starter là gì?
- Những cách được đề xuất để ngăn chặn các cuộc tấn công phát lại là gì?
Phiên bản dài
API có một điểm cuối /auth/token
mà từ đó frontend có thể nhận được mã thông báo JWT bằng cách cung cấp tên người dùng và mật khẩu. Phản hồi cũng bao gồm trạng thái xác thực, có thể là AUTHENTICATED hoặc PRE_AUTHENTICATED_MFA_REQUIRED .
Nếu người dùng yêu cầu MFA, mã thông báo được cấp với một cơ quan được cấp duy nhất PRE_AUTHENTICATED_MFA_REQUIRED
và thời gian hết hạn là 5 phút. Điều này cho phép người dùng truy cập điểm cuối /auth/mfa-token
nơi họ có thể cung cấp mã TOTP từ ứng dụng Authenticator của họ và nhận mã thông báo được xác thực đầy đủ để truy cập trang web.
Nhà cung cấp và mã thông báo
Tôi đã tạo tùy chỉnh của mình MfaAuthenticationProvider
mà thực hiện AuthenticationProvider
:
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// validate the OTP code
}
@Override
public boolean supports(Class<?> authentication) {
return OneTimePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
Và một OneTimePasswordAuthenticationToken
cái mở rộng AbstractAuthenticationToken
để giữ tên người dùng (lấy từ JWT đã ký) và mã OTP.
Cấu hình
Tôi có tùy chỉnh của mình WebSecurityConfigurerAdapter
, nơi tôi thêm tùy chỉnh của mình AuthenticationProvider
thông qua http.authenticationProvider()
. Tham gia vào JavaDoc, đây có vẻ là nơi thích hợp:
Cho phép thêm Trình xác thực bổ sung sẽ được sử dụng
Các phần có liên quan của tôi SecurityConfig
trông như thế này.
@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
Bộ điều khiển
Các AuthController
có các AuthenticationManagerBuilder
tiêm và kéo nó tất cả cùng nhau.
@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
Tuy nhiên, đăng bài chống lại /auth/mfa-token
dẫn đến lỗi này:
"error": "Forbidden",
"message": "Access Denied",
"trace": "org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for de.....OneTimePasswordAuthenticationToken
Tại sao Spring Security không nhận Nhà cung cấp xác thực của tôi? Gỡ lỗi bộ điều khiển cho tôi thấy đó DaoAuthenticationProvider
là Nhà cung cấp xác thực duy nhất trong AuthenticationProviderManager
.
Nếu tôi trưng ra MfaAuthenticationProvider
là đậu, thì đó là Nhà cung cấp duy nhất được đăng ký, vì vậy tôi nhận được điều ngược lại:
No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken.
Vì vậy, làm thế nào để tôi có được cả hai?
Câu hỏi của tôi
Cách được đề xuất để tích hợp bổ sung AuthenticationProvider
vào hệ thống được cấu hình Spring Boot Security Starter để tôi có được cả DaoAuthenticationProvider
tùy chỉnh và tùy chỉnh của riêng mình là MfaAuthenticationProvider
gì? Tôi muốn giữ mặc định của Spring Boot Scurity Starter và có thêm Nhà cung cấp riêng.
Ngăn chặn tấn công Replay
Tôi biết rằng thuật toán OTP tự nó không bảo vệ chống lại các cuộc tấn công phát lại trong lát cắt thời gian trong đó mã hợp lệ; RFC 6238 làm rõ điều này
Trình xác minh PHẢI KHÔNG chấp nhận lần thử thứ hai của OTP sau khi xác thực thành công đã được ban hành cho OTP đầu tiên, điều này đảm bảo chỉ sử dụng một lần OTP.
Tôi đã tự hỏi nếu có một cách được đề nghị để thực hiện bảo vệ. Vì mã thông báo OTP dựa trên thời gian, tôi nghĩ đến việc lưu trữ lần đăng nhập thành công cuối cùng trên mô hình của người dùng và đảm bảo chỉ có một lần đăng nhập thành công trong mỗi lát thời gian 30 giây. Điều này tất nhiên có nghĩa là đồng bộ hóa trên mô hình người dùng. Bất kỳ phương pháp tốt hơn?
Cảm ơn bạn.
-
Tái bút: vì đây là câu hỏi về bảo mật nên tôi đang tìm câu trả lời rút ra từ các nguồn đáng tin cậy và / hoặc chính thức. Cảm ơn bạn.