+2

Kiến trúc bảo mật trọng Spring

Bài viết sẽ đề cập đến những khái niệm về spring security và việc apply nó vào trong một ứng dụng web. Bạn có thể sử dụng guide này khi cần hiểu ở mức high level về việc bảo mật ứng dụng như thế nào và làm sao để customized Spring security, hoặc chỉ đơn giản là bạn muốn biết về độ bảo mật của một ứng dụng với spring security.

Bài viết này không nhằm mục đích giải quyết các vấn đề cơ bản liên quan đến spring security, nhưng nó sẽ rất hữu ích cho những người mới và cả những người đã có kinh nghiệm về spring security. Spring Boot cũng được ứng dụng khá nhiều từ spring security vì nó cung cấp một số behaviour mặc định cho biệc bảo mật của 1 ưng dụng. Spring security cũng khá hưu dụng cho hầu hết các kiến trúc. Khái niệm đầu tiên cần tìm hiều trong spring security đó là vấn đề liên quan đến việc Authentication và Authorization.

Tính bảo mật của ứng dụng có thể bị phá bỏ nếu mối quan hệ giữa authentication (bạn là ai) và authorization (bạn được phép làm gì?) không gắn kết với nhau một cách chặt chẽ. Có một số người lại muốn dụng thuật ngũ "access control" thay cho thuật ngữ "authorization". Spring security có một kiến trúc mà nó được design để phân chia việc xác thực và cấp quyền cho người sử dụng hệ thống, và nó có những strategies cũng như các phần mở rộng cho 2 sự kiện này.

1. AUTHENTICATION

Interface chính cho việc authentication là AuthenticationManager, trong interface này chỉ có 1 method như dưới đây:

  public interface AuthenticationManager {

  Authentication authenticate(Authentication authentication)
    throws AuthenticationException;

}

Một instance mà nó thực hiện AuthenticationManager có thể làm 1 trong 3 việc sau khi nó implement method authenticate(): 1. Trả về 1 object Authentication (thường thì với trường hợp attribute authenticated=true) nếu nó kiểm tra được các giá trị input là hợp lệ. 2. Trả về 1 exception (AuthenticationException) nếu các giá trị input không hợp lệ 3. Trả về null nếu nó không thể xử lý.

AuthenticationException là một Runtime Exception. Nó thường được xử lý bới application, tuỳ thuộc vào cách thức cũng như mục đích của ứng dụng. Nói cách khác thì người code sẽ không mong muốn việc catch và handle exception dạng này. Ví dụ, một ưng dụng web sẽ sinh ra 1 trang mà nó cho người dùng biết rằng việc xác thực đã thật bại, và ứng dụng sẽ trả về mã 401 cho người dùng, với header WWW-Authenticate (tuỳ thuộc vào context của người dùng).

Instance mà thực thi interface AuthenticationManager phổ biến nhất được sử dụng là ProviderManager, no cũng thực thi một loạt các behaviour của AuthenticationProvider. AuthenticationProvider khá giống AuthenticationManager nhưng nó thêm một method cho phép truy vấn nếu method này được gọi với việc truyền vào kiểu Authentication như bên dưới:

 public interface AuthenticationProvider {

    Authentication authenticate(Authentication authentication)
            throws AuthenticationException;

    boolean supports(Class<?> authentication);

}

Đối số Class<?> trong method supports() thật chỉ là 1 dạng ngắn gọn của cú pháp sau Class<? extends Authentication>. ProviderManager instance có thể support nhiều cơ chế xác thực khác nhau trong cúng 1 application bởi việc điều phối việc này cùng với AuthenticationProviders. Nếu ProviderManager không thể nhận biêt được kiểu của instance Authentication, nó sẽ bỏ qua.

Một ProviderManager có thể được extend từ một class cha tuỳ chọn, nơi mà nó có thể được xem xét nếu tất car các provider trả về kiểu null. Nếu class cha này không available thì ứng dụng sẽ trả về 1 AuthenticationException exception.

Có những ứng dụng có một loạt các logic để bảo vệ tài nguyên cho ứng dụng ( ví dụ: tất cả các web resources thứ mà được truy cập với pattern /api/**), và mỗi logic này sẽ được xử lí bởi một AuthenticationManager riêng. Thường thì, đó là một ProviderManager, và nó có chung class cha. Class cha này là một loại tài nguyên chung, đóng vai trò như một nguồn dự phòng cho tất cả các providers con. Kiến trúc này được mô tả như ở dưới đây:

1.png

EXTENSION: - Tuỳ chỉnh Authentication Managers Spring security cung cấp các class tiện ích cho phép cài đặt nó một cách nhanh chóng vào một ứng dụng. Một trong những class đó là AuthenticationManagerBuilder thứ mà khá tiện ích cho việc cài đặt in-memory, jDBC hoặc LDAP, hoặc cho việc thêm một instance của UserDetailsService. Dưới đây là một ví dụ cho việc cài đặt toàn cục cho AuthenticationManager:

@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

   ... // web stuff here

  @Autowired
  public initialize(AuthenticationManagerBuilder builder, DataSource dataSource) {
    auth.jdbcAuthentication().dataSource(dataSource).withUser("dave")
      .password("secret").roles("USER");
  }

}

Ví dụ trên là từ một ứng dụng web, việc sử dụng annotation @Autowired trong 1 bean ở trên là một syntax cho việc build global AuthenticationManager. Dưới đây là 1 cách cài đặt khác cho local AuthenticationManager:

`@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

  @Autowired
  DataSource dataSource;

   ... // web stuff here

  @Override
  public configure(AuthenticationManagerBuilder builder) {
    auth.jdbcAuthentication().dataSource(dataSource).withUser("dave")
      .password("secret").roles("USER");
  }

}`

Việc sử dụng @Override method configure() là một cách cài đặt local AuthenticationManager. Trong ứng dụng sử dụng spring boot việc cài đặt AuthenticationManager mặc định là global.

2. AUTHORIZATION

Sau khi việc xác thực thành công, ứng dụng sẽ thực hiện việc phân quyền cho người dùng với thành phần xử lý chính ở đây là AccessDecisionManager. Spring security cung cấp 3 class thực thi interface này: AffirmativeBased, ConsensusBased, UnanimousBased. Việc thực thi của 3 class này giống như DecisionVoter. Một DecisionVoter sẽ quản lý Authentication và một Object sau khi authenticate thành công với các attributes mà nó được thể hiện trong interface ConfigAttribute. Các instance thực thi từ ConfigAttribute bao gồm metadata để xác định cấp độ quyền truy cập của object. ConfigAttribute là môt interface nhưng nó chỉ có 1 method khá chung chung và nó trả về kiểu String, vì vậy các String này mã hoá theo 1 vài cách nào đó để đưa ra các quy luật về việc định nghĩa ai là người có quyênf truy cập. Thông thường ConfigAttribute là tên vai trò của user, ví dụ: ROLE_ADMIN or ROLE_AUDIT. Và chúng thường có định dạng đặc biệt, ví dụ với prefix: ROLE_, hoặc là một biểu thức cần được tính toán. Instance được sử dụng mặc định cho autharization thường là AffirmativeBased.

Ngôn ngữ thường được sử dụng cho các attribute của ConfigAttribute là Spring Expression Language (SpEL), ví dụ isFullyAuthenticated() && hasRole('FOO'). Ngôn ngữ này được hỗ trợ bởi 1 DecisionVoter thứ mà có thể xử lý các biểu thức và tạo context cho nó. Để mở rộng biểu thức của SpEL, người sử dụng cần implement SecurityExpressionRoot hoặc SecurityExpressionHandler.

TỔNG KẾT:

Như vậy, qua bài viết này chúng ta đã hiểu thêm về các thành phần và việc mở rộng khi sử dụng spring security trong một ứng dụng. Từ đó, việc xây dựng một ứng dụng hoặc áp dụng spring security cho ứng dụng cũng sẽ dễ dàng và chính xác hơn.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí