프로젝트가 시작되었따... 빠르게 알고가야하는 개념에 대해서 정리하면서 공부해보자!
구조로 보면 더 이해가 쉬워서 다양한 spring security 구조 자료를 가져왔다!
Spring Security
Spring Framework 기반 애플리케이션에 인증(Authentication)과 권한 부여(Authorization)를 처리하기 위한 보안 프레임 워크이다!
구성 요소
- Authentication (인증)
- 사용자가 누구인지 확인하는 과정을 거친다.
- 사용자 이름과 비밀번호, 토큰 등을 사용한다.
- Authorization (권한 부여)
- 인증된 사용자가 어떤 작업을 수행할 권한이 있는지 확인한다.
- URL, 메서드, 리소스 접근 제어한다.
- Filter Chain
- 보안 로직은 일련의 필터 체인으로 작동 한다.
- 요청이 들어오면 필터 체인을 거치면서 인증과 권한 검사를 수행한다.
- Security Context
- 인증된 사용자의 정보를 저장하는 컨테이너 역할을 한다.
- 애플리케이션 전반에서 인증 정보를 쉽게 사용할 수 있도록 제공한다.
- UserDetailsService
- 사용자 정보를 가져오는 인터페이스이다.
- 커스텀 구현으로 데이터베이스 연동이 가능하다.
- SecurityBuilder
- 빌더 클래스로서 웹 보안을 구성하는 빈 객체와 설정 클래스들을 생성하는 역할을 하며 WebSecurity, HttpSecurity가 있다.
- SecurityConfiguer를 포함하고 있다.
- SecurityConfiguer
- Http 요청과 관련된 보안 처리를 담당하는 필터들을 생성하고 여러 초기화 설정에 관여한다.
- 인증 및 인가 초기화 작업은 SecurityConfigurer에 의해 진행된다.
내부 동작 과정
- 클라이언트 요청
- 사용자가 URL 또는 API에 요청을 보낸다.
- Filter Chain 작동
- Spring Security의 필터 체인이 요청을 가로채 처리.
- UsernamePasswordAuthenticationFilter 등 다양한 필터가 있다.
- 요청의 인증 정보를 파싱하고 처리 한다.
- AuthenticationManager
- 요청을 AuthenticationManager에 전달한다.
- 인증 정보를 검증하고 결과를 반환 한다.
- UserDetailsService와 PasswordEncoder
- UserDetailsService는 데이터베이스에서 사용자 정보를 로드 한다.
- 비밀번호 검증 시 PasswordEncoder로 암호화된 비밀번호를 비교 한다.
- Security Context에 저장
- 인증 성공 시 SecurityContext에 인증 정보를 저장 한다. (이정보는 애플리케이션 전반에서 참조 가능하다)
- 요청 처리 후 응답
- 필터 체인을 통과한 요청은 컨트롤러에 도달하고 컨트롤러에서 비즈니스 로직 처리 후 응답을 반환 한다.
Spring Security 기본 설정
Security Configuration 클래스
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public/**").permitAll() // 공용 리소스
.anyRequest().authenticated() // 인증 필요
.and()
.formLogin(); // 기본 로그인 페이지
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// 1. 선언적인 보안 설정
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/public/**").permitAll()
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
// 2. 다양한 보안 기능 기본 제공
.formLogin(form -> form
.loginPage("/login")
.permitAll()
)
// 3. CSRF 보호 자동 활성화
.csrf(csrf -> csrf.enable());
return http.build();
}
}
UserDetailsService 구현
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 예: 사용자 정보 DB 조회
return User.builder()
.username("user")
.password(new BCryptPasswordEncoder().encode("password"))
.roles("USER")
.build();
}
}
Spring Security를 사용하는게 뭐가 좋을까?
Spring Secufity를 사용하지 않은 경우
@RestController
public class UserController {
@PostMapping("/login")
public String login(HttpSession session, String username, String password) {
// 1. 직접 비밀번호를 평문으로 저장하거나, 암호화 방식을 직접 구현해야 함
User user = userRepository.findByUsername(username);
if (user != null && password.equals(user.getPassword())) {
// 2. 세션에 직접 사용자 정보를 저장
session.setAttribute("user", user);
return "로그인 성공";
}
return "로그인 실패";
}
@GetMapping("/admin")
public String adminPage(HttpSession session) {
// 3. 매 요청마다 권한 체크를 직접 구현
User user = (User) session.getAttribute("user");
if (user != null && user.hasRole("ADMIN")) {
return "관리자 페이지";
}
return "접근 거부";
}
}
- 보안 취약점 발생 위험
- SQL 인젝션에 취약할 수 있다.
- 세션 하이재킹에 취약할 수 있다.
- CSRF(Cross-Site Request Forgery) 공격에 노출될 수 있다.
- XSS(Cross-Site Scripting) 공격에 취약할 수 있다.
- 개발 생산성 저하
- 모든 보안 관련 로직을 직접 구현해야 한다.
- 각 컨트롤러마다 권한 체크 코드가 중복된다.
- 비밀번호 암호화, 인증 토큰 관리 등을 직접 구현해야한다.
Spring Security... 좀 더 알고싶어!
아쉬운 부분을 좀더 채워보았다!
URL 패턴(antMatchers 등)
- Spring Security에서는 URL 경로에 따라 권한을 설정할 수 있다.
- 특정 URL은 누구나 접근 가능하게 하지만, 다른 URL은 인증된 사용자만 접근 가능하게 하고싶을 때 사용한다.
antMatchers란?
- antMatchers는 URL 패턴을 정의하는 데 사용된다.
- 특정 URL 경로에 대해 허용 여부나 권한 조건을 설정한다.
- 경로 패턴은 Ant-style 패턴을 사용한다.
- * : 현재 경로의 모든 항목과 매칭 (한 단계)
- ** : 하위 모든 경로와 매칭 (여러 단계)
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/public/**").permitAll() // "/public/" 이하 모든 경로는 누구나 접근 가능
.antMatchers("/admin/**").hasRole("ADMIN") // "/admin/" 이하 경로는 ADMIN 역할만 접근 가능
.anyRequest().authenticated(); // 나머지 요청은 인증 필요
}
메서드 수준(@PreAuthorize, @PostAuthorize) 권한 설정
왜 메서드 수준 권한 설정이 필요할까?
- URL 단위 권한 설정만으로는 모든 보안 요구를 충족하기 어렵다.
- 특정 메서드(비즈니스 로직)에 대해 더 세부적으로 접근 권한을 제어할 수 있다.
@PreAuthorize와 @PostAuthorize 란?
- @PreAuthorize: 메서드 호출 전에 조건을 확인하여 권한을 검사한다.
- @PostAuthorize: 메서드 실행 후 반환값을 기반으로 권한을 검사한다.
@Service
public class AdminService {
@PreAuthorize("hasRole('ADMIN')")
public void performAdminTask() {
// 이 메서드는 ADMIN 역할을 가진 사용자만 호출 가능
System.out.println("Admin task executed.");
}
@PostAuthorize("returnObject.owner == authentication.name")
public MyResource getResource(Long id) {
// 반환된 리소스의 소유자(owner)가 현재 사용자와 일치하는 경우만 접근 허용
return new MyResource("exampleResource", "user123");
}
}
CSRF란 무엇일까?
CSRF(Cross-Site Request Forgery)는 웹 애플리케이션에서 발생할 수 있는 보안 취약점 중 하나이다.
공격자가 사용자를 속여 원치 않는 요청을 서버로 보내도록 유도하는 공격 방식이다.
CSRF 공격의 작동 방식
- 사용자가 신뢰할 수 있는 사이트에 로그인하고 세션을 유지한다.
- 공격자가 악의적인 웹사이트(또는 이메일)를 준비하고 사용자가 해당 웹사이트를 방문하도록 유도한다.
- 악의적인 웹사이트에서 사용자의 인증 정보를 활용해 신뢰할 수 있는 사이트로 비정상적인 요청을 보낸다.
- 서버는 요청이 사용자의 브라우저에서 온것이므로 이를 신뢰하고 처리하게 된다.
예제 시나리오
- 피해자는 은행 사이트에 로그인 중이다.
- 공격자가 피해자를 속여 악성 링크를 클릭하도록 유도한다.
- 브라우저는 로그인 상태를 유지하고 있으므로, 요청이 정상으로 보인다.
- 결과적으로, 피해자의 계좌에서 공격자 계좌로 돈이 이체된다.
Spring Security에서 CSRF 방어
Spring Security는 기본적으로 CSRF 보호를 활성화 합니다.
CSRF 활성화의 동작
- 서버는 CSRF 토큰을 생성하고 클라이언트에 전달한다.
- 클라이언트는 요청 시 이 토큰을 함께 서버로 보낸다.
- 서버는 요청에 포함된 토큰과 저장된 토큰을 비교해서 유효성을 확인한다.
- 토큰이 없거나 일치하지 않으면 요청을 거부한다.
하ㅏ하하ㅏㅏ.. Spring Security 알아야할께 더 있지만 프로젝트를 하면서 더 알아보자!
** 그냥 하루하루 개인 공부한 것을 끄적 거리는 공간입니다.
이곳 저곳에서 구글링한 것과 강의 들은 내용이 정리가 되었습니다.
그림들은 그림밑에 출처표시를 해놓았습니다.
문제가 될시 말씀해주시면 해당 부분은 삭제 하도록하겠습니다. **
'public void static main > Java' 카테고리의 다른 글
[Spring Security] JWT(Json Web Token) (1) | 2025.01.13 |
---|---|
[Spring] Filter, AOP, Interceptor 그리고 Middleware (0) | 2025.01.02 |
[JAVA] 불변객체, 가변객 뭔지는 알겠는데 자세히 좀 더 알아보자 (1) | 2024.12.25 |
[JAVA] LinkedList 알꺼같으면서도 모르겠다. (0) | 2024.12.23 |
[JAVA] 타입 캐스팅 시 발생하는 오버플로우? (0) | 2024.12.22 |
댓글