CS/웹개발
Spring Security
hyunji1109
2025. 1. 4. 16:02
애플리케이션의 보안(인증과 권한, 인가 등)을 담당하는 스프링 보안 프레임워크이다.
Spring Security는 '인증'과 '권한'에 대한 부분을 Filter 흐름에 따라 처리하고 있다.
특징
- 인증(Authentication)
- 사용자가 누구인지 확인.
- 권한 부여(Authorization)
- 사용자가 특정 리소스나 작업에 접근할 수 있는지 결정.
- 보안 기능 제공
- CSRF 보호, 세션 관리, 암호화 지원.
- 확장 가능성
- 다양한 보안 요구사항에 맞게 커스터마이징 가능.
- 통합
- Spring Boot와 자연스럽게 통합되어 설정 및 사용이 간단.
CSRF(Cross-Site Request Forgery)
사용자의 의도와는 무관하게 공격자가 특정 웹 애플리케이션에 사용자 권한을 이용해 악의적인 요청을 보낼 수 있는 취약점
Spring Security는 기본적으로 인증 절차를 거친 후에 인가 절차를 진행하게 되며, 인가 과정에서 해당 리소스에 대한 접근 권한이 있는지 확인을 하게 된다.
Spring Security에서는 이러한 인증과 인가를 위해 Principal을 아이디로, Credential을 비밀번호로 사용하는 Credential 기반의 인증 방식을 사용한다.
동작 과정
- 사용자가 로그인 정보 id password 를 로그인 인증 Authentication 요청
- AuthenticationFilter 가 정보를 가로채 UsernamePasswordAuthentication Token 을 생성하여 (Authentication 객체) AuthenticationManager 에게 Authentication 전달
- AuthenticationManager 인터페이스를 거쳐 Autehntication Provider 에게 정보 전달, 등록된 AuthenticationProvider 를 조회하여 인증 요구 한다.
- AutenticationProvider는 UserDetailService 를 통해 입력받은 (3)의 사용자 정보를 DB에서 조회한다.
- .support()메소드가 실행 가능한지 체크
- authenticate() 메소드를 통해 DB에 저장된 이용자 정보와 입력한 로그인 정보 비교
- DB 이용자 정보 : UserDetailService 의 loadUserByUsername() 을 통해 불러옴
- 입력 로그인 정보 : (3)에서 받았던 Authentication 객체 UsernameAuthentication Token
- 일치하는 경우 Authentication 반환
- AuthenticationManager 는 Authentication 객체를 AutenticationFilter 로 전달
- AuthenticationFilter 는 전달 받은 Authentication 객체를 LoginSuccessHandler로 전송 하고 SecurityContextHolder 에 담는다.
- 성공시 AuthenticationSucesshandle 실패시 AuthenticationFailureHandle 실행
① 사용자 요청
- 사용자가 서버에 HTTP 요청을 보냄
② Filter Chain 실행
- Spring Security의 Filter Chain에서 요청을 가로채 보안 관련 처리를 수행
- 주로 UsernamePasswordAuthenticationFilter가 인증을 처리
③ AuthenticationManager
- 인증 요청을 처리하는 핵심 클래스. Authentication 객체를 받아 인증 성공 여부를 결정
④ SecurityContext
- 인증 성공 시 사용자 정보를 SecurityContext에 저장
- SecurityContext는 세션 또는 스레드에 바인딩되어 사용 중에 참조 가능
⑤ 권한 부여 검사
- 요청한 URL, 메서드, 리소스에 접근 권한이 있는지 확인
- 허용되지 않은 경우 403(Forbidden) 상태 코드 반환
구성 요소
1. SecurityContext
- 현재 인증된 사용자와 관련된 정보를 저장
- SecurityContextHolder를 통해 애플리케이션 어디서나 접근 가능
@RestController
public class UserController {
@GetMapping("/user")
public String getCurrentUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return "Current User: " + authentication.getName();
}
}
2. Authentication
- 사용자의 인증 정보를 포함하는 인터페이스
- 인증 전에는 사용자 정보만 포함하며, 인증 후에는 권한 및 세부 정보도 추가
@RestController
public class AuthController {
@PostMapping("/authenticate")
public String authenticateUser() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth.isAuthenticated()) {
return "Authenticated user: " + auth.getName();
}
return "Not Authenticated";
}
}
3. GrantedAuthority
- 사용자에게 부여된 권한(역할)을 나타냄
- 예: ROLE_USER, ROLE_ADMIN
@RestController
public class RoleController {
@GetMapping("/admin")
public String checkAdminAccess(Authentication authentication) {
boolean isAdmin = authentication.getAuthorities().stream()
.anyMatch(auth -> auth.getAuthority().equals("ROLE_ADMIN"));
return isAdmin ? "Welcome Admin!" : "Access Denied!";
}
}
4. AuthenticationManager
- 인증 과정을 관리
- AuthenticationProvider를 통해 인증 요청을 처리
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("{noop}password").roles("USER")
.and()
.withUser("admin").password("{noop}admin").roles("ADMIN");
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
5. UserDetailsService
- 사용자 정보를 로드하는 서비스 인터페이스
- 데이터베이스나 메모리 등에서 사용자 정보를 가져오는 데 사용
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if ("user".equals(username)) {
return User.withUsername("user")
.password("{noop}password")
.roles("USER")
.build();
} else if ("admin".equals(username)) {
return User.withUsername("admin")
.password("{noop}admin")
.roles("ADMIN")
.build();
} else {
throw new UsernameNotFoundException("User not found");
}
}
}
6. PasswordEncoder
- 비밀번호를 암호화하거나 비교하는 데 사용
- BCryptPasswordEncoder가 가장 널리 사용됨
@Configuration
public class PasswordConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
String rawPassword = "password";
String encodedPassword = passwordEncoder().encode(rawPassword);
System.out.println(encodedPassword);
7. Filter Chain
- HTTP 요청을 가로채 보안 검사를 수행하는 여러 필터들의 체인
- 주요 필터
- UsernamePasswordAuthenticationFilter
- 기본 인증 처리
- BasicAuthenticationFilter
- Basic 인증 처리
- CsrfFilter
- CSRF 공격 방어
- UsernamePasswordAuthenticationFilter
8. HttpSecurity
- 보안 설정을 구성하는 클래스
- URL 접근 제어, CSRF 설정, 로그인/로그아웃 설정 등을 정의
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable() // CSRF 비활성화
.authorizeRequests()
.antMatchers("/api/public").permitAll()
.antMatchers("/api/user").hasRole("USER")
.antMatchers("/api/admin").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout")
.permitAll();
}