보안의 필요성
공격자는 여러 방법으로 Wi-Fi 네트워크나 라우터에 접근하여 그 안을 흐르는 데이터를 제어하거나 모니터링할 수 있습니다.
인터셉션이 발생하는 방법
공격자가 사용자와 서버 사이의 데이터를 몰래 엿보거나 수정하는 행위입니다.
- 중간자(MitM) 공격 : 공격자가 사용자와 서버 사이에서 트래픽을 조작하거나 가로챔
- 패킷 스니핑 : 네트워크를 통해 오가는 데이터 패킷을 몰래 가로채 분석
스푸핑(위장) 공격 방법
스푸핑은 속임수를 통해 신뢰받는 사용자나 시스템으로 가장하여 불법적인 접근이나 데이터를 탈취하려는 공격입니다
- a. IP 스푸핑: 공격자가 자신이 보내는 패킷의 IP 주소를 위조하여 요청이 신뢰할 수 있는 IP 주소에서 온 것처럼 보이게 합니다.
- b. 세션 하이재킹: 공격자가 유효한 세션 ID(예: 세션 쿠키를 가로챔)를 획득하여 합법적인 사용자로 가장합니다.
- c. 사이트 간 요청 위조(Cross-Site Request Forgery, CSRF): 공격자가 합법적인 사용자를 속여 인증된 서버에 의도하지 않은 사용자 요청을 보내도록 함으로써, 마치 그들이 클라이언트인 것처럼 프로토콜을 전송하게 합니다.
이러한 위험성때문에 기본적으로 트래픽 감청과 클라이언트 모방의 위험성을 전제로 보안성을 생각하여 개발이 필요함.
어플리케이션 Security의 기본개념
어플리케이션 개발자는 어플리케이션 레벨에서의 보안만 집중하면되며, 어플리케이션 레벨에서는 아래와 같은 5가지 핵심요소가존재한다.
1. Authentication(인증) : Client의 신분을 확인하는 과정으로, Client가 본인임을 증명하기 위해 고유한 정보를 제공.
- Knowledge Authentication : PW, Pin Code, 비밀질문 등 사전에 서로 알고있는 지식으로 인증함.
- Posession Based : SMS 인증, KEYCard 인증 등 소유한 물건을 사용하여 인증.
2. Principal : 현재 인증절차를 거쳐 로그인 상태인 유저. 현재 인증을 완료한 상태에서 시스템에 로그인한 사용자.
3. Authorization(권한) : Client가 요청이 Client의 권한 내에 있는지 확인
4. Authority : Client 리소스에 접근하거나 작업을 수행할 수 있는 권한 단위
5. Role : Authority의 그룹.
- 여러 Authority를 묶어서 관리하기 위한 개념이며 사용자는 역할(Role)을 부여받아 Authority를 간접적으로 보유.
- ROLE_ADMIN은 READ_PRIVILEGE, WRITE_PRIVILEGE, DELETE_PRIVILEGE를 포함할 수 있음.
스프링 Security Authentication 전체구조

Spring Security의 인증(Authentication) 과정 정리
spring security는 일련의 필터이다. 필터를 통과하면서 발생하는 로직들을 추가한 것이라고 생각하면 됨. 필터들은 request가 컨트롤러에 도달하기 전에 요청들을 검증하고 로직을 수행하고 결과값을 반환하는 역할을 함.
- 사용자 인증 요청
- 애플리케이션은 유저의 신분을 확인하기 위해 이름(username)**과 비밀번호(password) 요구함.
- 사용자의 로그인 요청은 필터체인을 통과하면서 가장 앞에 있는 Authentication 관련 필터를 거쳐 처리됨.
- 기본설정시 : 필터 내에 존재하는 AuthenticationManager는 적절한 AuthenticationProvider를 찾아 해당 요청을 위임(delegation)하여 처리합니다. 여러 개의 AuthenticationProvider가 존재할 수 있으며, 각각 특정 인증 방식(예: 사용자 이름/비밀번호, OTP 등)에 특화되어 사용자 인증정보 검증
- 커스텀 구현시 : 구현 로직에 따라서 인증을 진행하며 주로 1. UserDetailService를 통해서 ID,PW일치여부를 검증 혹은 2. 최초로그인시 발부받은 키를 검증함
- 인증 성공 시 Authentication 객체 반환
- Authentication 객체를 SecurityContext저장
- Authentication 객체는 인증과 관련된 정보를 담고 있는 DTO로 사용자 정보를 포함
- 사용자 정보는 credentials, principal은 UserDetails 객체로 표현되며, 사용자 정보(이름, 권한, 계정 상태 등)를 포함함.
- 인증이 완료된 후, SecurityContext에 Authentication 객체를 저장하여 이후 요청에서 사용자의 인증 상태를 확인할 수 있도록 함.
SecurityContext
SecurityContext**는 Spring Security에서 사용자의 인증(Authentication) 및 권한(Authorization) 정보를 관리하는 중앙 저장소입니다. 애플리케이션의 요청(Request)이 처리되는 동안, 현재 사용자의 인증 상태와 권한 정보를 SecurityContext에 저장합니다.현재 요청의 SecurityContext를 저장하고 접근하는 데 사용됩니다. 기본적으로 스레드 로컬(ThreadLocal) 저장소를 사용하여 요청별로 독립된 SecurityContext를 관리합니다.
Authentication auth = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(auth);
SecurityContext에 저장되는 정보
SecurityContext는 사용자의 인증(Authentication) 및 권한(Authorization) 정보를 포함합니다. Spring Security에서 이 정보는 Authentication 객체에 캡슐화되며, 다음과 같은 데이터가 포함됩니다. Spring Security는 UserDetailsService 인터페이스를 통해 사용자의 인증 및 권한 정보를 로드합니다.
Principal | 인증된 사용자의 정보(주로 UserDetails 객체). |
Credentials | 자격 증명(예: 비밀번호). 인증 후 보통 제거됩니다(보안 이유). |
Authorities | 사용자의 권한(Role) 목록. |
Authenticated | 사용자가 인증되었는지 여부(Boolean 값). |
스레드 로컬
ThreadLocal은 Java에서 제공하는 클래스로, 각 스레드마다 독립적인 변수 값을 저장할 수 있는 메커니즘을 제공합니다. 이 변수는 스레드가 종료될 때까지 해당 스레드 내에서만 접근할 수 있습니다. 즉, ThreadLocal에 저장된 값은 각 스레드의 고유 데이터로 간주되며, 다른 스레드와 공유되지 않습니다.
로컬 변수는 데이터를 메서드 내부에서만 사용할 때 유용합니다. 메서드 호출이 끝나면 변수가 사라지므로 스레드 간에 공유될 가능성이 없습니다.
스프링 Security Filter
Spring Security는 애플리케이션에 Security Filter Chain을 자동으로 추가합니다.pringsecurity는 Dispatcher Servelet으로 가기전에 통과해야하는 Chain of Filter을 말한다. 이 필터를 통해서 서블릿으로 들어가는 모든 request에 대해서 Intercept하여 승인, 거절,
인증, 권한부여 등과 같은 처리를 해준다.
기본적으로 표준 서블릿 컨테이너는 자체 표준으로 사용하는 필터를 등록할 수 있다. Spring Security는 표준 서블릿 컨테이너의 필터 외에도 Spring Bean으로 구현한 모든 필터를 등록할 수 있다.
FilterChainProxy:
- Spring Security의 필터 체인의 메인 진입점 역할을 하는 특별한 프록시 필터입니다. Spring Security에서 HTTP 요청이 처리될 때 **FilterChainProxy**가 모든 요청을 가로챕니다.
- MVC패턴에서의 Dispatcher처럼 등록된 SecurityFilterChain들을 탐색하여 요청 URL과 매칭되는 SecurityFilterChain 검색하여, 작업을 위임하고 보안을 처리합니다.
FilterStack
Spring Security를 추가하면 기본설정으로 FilterStack 들이 추가되어 동작한다. HTTP 요청(Request)이 애플리케이션에 도달하기 전에, 그리고 응답(Response)이 클라이언트로 반환되기 전에 보안 관련 작업을 처리하는 일련의 필터(Filter)들의 체인입니다.
- WebAsyncManagerIntegrationFilter : 일반적인 요청은 한 번의 요청과 응답으로 끝납니다. 그러나 비동기 요청에서는 백그라운드 스레드에서 작업이 처리되기 때문에 보안 컨텍스트(SecurityContext)가 사라질 위험이 있습니다. 비동기 요청에서도 **SecurityContext**와 같은 보안 정보를 올바르게 유지하도록 보장합니다.
- SecurityContextPersistenceFilter : 세션 상태(Session-based Authentication)에서 HttpSession을 사용하여 이전 요청의 SecurityContext를 복원하거나 초기화. 요청이 시작되면 세션이나 저장소에서 기존의 SecurityContext(인증 정보)를 불러옵니다. 요청이 끝날 때 SecurityContext를 저장하거나 정리합니다.
- HttpSession이란 무엇인가? : 웹 애플리케이션에서 클라이언트(사용자)와 서버 간의 상태 정보를 유지하기 위해 사용하는 Java EE 표준 인터페이스입니다. 사용자가 서버에 처음 요청을 보내면, 서버는 고유한 **세션 ID(Session ID)**를 생성합니다. 서버는 클라이언트의 요청과 관련된 데이터를 세션 객체에 저장합니다. (예: 사용자의 로그인 상태, 인증 정보, 사용자 설정 등.) 클라이언트가 이후 요청을 보낼 때, 세션 ID를 포함한 쿠키를 서버로 전송합니다.서버는 세션 ID를 기반으로 해당 클라이언트와 연관된 데이터를 찾아 세션을 복원합니다.
- HeaderWriterFilter :HTTP 응답 헤더에 보안 관련 헤더를 추가하여 다양한 보안 위협으로부터 보호합니다. (예: X-Frame-Options, Strict-Transport-Security 등).
- CsrfFilte : CSRF 공격을 방지하는 필터. 서버는 각 세션마다 고유한 CSRF 토큰을 생성합니다. 이 토큰은 클라이언트에 전달되며, 보통 HTML 폼의 숨겨진 필드로 포함됩니다. 클라이언트가 상태를 변경하는 요청(예: POST, PUT, DELETE)을 보낼때 CSRF토큰도 같이 전송되며 서버는 이 CSRF 토큰을 검증하는 방식으로 CSRF 공격을 방지한다.
- LogoutFilter : 사용자의 로그아웃 요청을 처리하고, 인증 정보를 제거하며, 세션을 무효화합니다.
- UsernamePasswordAuthenticationFilter :사용자 이름/비밀번호 기반 로그인을 처리. Spring Security에서 기본적인 로그인 과정을 처리하는 필터입니다. 폼 기반 로그인 요청에서 사용자 이름(username)과 비밀번호(password)를 처리. AuthenticationManager를 통해 인증을 처리하며, 주로 DaoAuthenticationProvider와 연동. UserDetailsService를 사용해 사용자 정보를 로드. UserDetailsService가 없다면, 인증에 필요한 사용자 데이터를 가져올 수 없음.
- RequestCacheAwareFilter : 인증되지 않은 요청이 캐시된 경우, 해당 요청을 복원.
- SecurityContextHolderAwareRequestFilter : 인증된 사용자를 위한 요청 래퍼를 제공.
- AnonymousAuthenticationFilter : 인증되지 않은 사용자를 "익명 사용자"로 처리.
- SessionManagementFilter : 세션 생성 및 관리, 세션 고정 공격 방지.
- ExceptionTranslationFilter : 인증 및 권한 예외를 처리 (예: 403 Forbidden 응답 생성).
- FilterSecurityInterceptor : URL 기반 접근 제어 및 권한 확인 (최종 보안 필터).
스프링 Security Context
한번 Jwt인증을 통해서 Authentication 객체를 SecurityContext에 넣었다고 한다면, 더이상 해당 request는 Authentication 과정을 거치지 않아도 된다. 그리고 이 인증은 thread localvariable에 저장되어서 thread의 생명주기가 끝날때까지 다시 Authentication과정을 거치지 않아도 된다. 특히, method 별로 권한을 설정하였을 경우 다시 Authentication을 통해 role을 parsing할 필요가 없어진다.
스프링 Security Authentication Provider
Spring Security에서 AuthenticationProvider는 인증 요청을 처리하는 핵심 인터페이스입니다. 사용자 인증 정보를 검증하고, 인증이 성공하면 인증된 Authentication 객체를 반환합니다. 이 객체는 이후 요청 처리에서 인증된 사용자 정보를 제공합니다.
핵심 메서드
- authenticate(Authentication authentication):
- Authentication 객체를 받아 사용자 인증을 수행합니다.
- 인증에 성공하면 인증된 Authentication 객체를 반환.
- 인증 실패 시 AuthenticationException을 던집니다.
Spring Security에서 기본 제공하는 AuthenticationProvider
Spring Security는 여러 가지 기본 구현을 제공합니다:
a. DaoAuthenticationProvider
- 데이터베이스를 기반으로 사용자 이름과 비밀번호 인증.
- UserDetailsService를 통해 사용자 정보를 로드.
- 비밀번호는 PasswordEncoder를 사용해 해시된 값과 비교.
b. JwtAuthenticationProvider (직접 구현 필요)
- JWT 토큰을 검증하고 사용자 인증.
- 토큰의 서명, 만료 시간, Claims 등을 검증.
- 대부분의 경우 직접 구현해야 함.
스프링 UserdetailService
UserDetailsService는 Spring Security에서 사용자 인증 정보를 가져오기 위해 사용되는 핵심 인터페이스입니다. 데이터베이스나 다른 저장소에서 사용자 정보를 로드하고, Spring Security의 인증 과정에서 이를 활용합니다.
정의
- UserDetailsService는 사용자 이름(username)을 기반으로 사용자 세부 정보를 로드하는 역할을 수행합니다.
- 사용자 세부 정보는 UserDetails 인터페이스를 구현한 객체로 반환됩니다.
- 기본적으로 사용자 인증 과정에서 사용자 정보를 제공하는 역할을 합니다.
주요 메서드
- UserDetails loadUserByUsername(String username):
- 주어진 사용자 이름(username)에 따라 사용자 정보를 로드.
- 성공적으로 로드하면 사용자 정보를 담은 UserDetails 객체 반환.
- 사용자가 존재하지 않거나 문제가 있을 경우 예외(UsernameNotFoundException)를 던집니다.
UserDetails
- UserDetails는 Spring Security가 인증 및 권한 부여를 위해 사용하는 사용자 정보 객체입니다.
- UserDetailsService는 이 UserDetails 객체를 반환합니다.
UserDetails의 주요 메서드
- getUsername(): 사용자 이름 반환.
- getPassword(): 비밀번호 반환.
- getAuthorities(): 사용자 권한 목록 반환.
- isAccountNonExpired(): 계정 만료 여부.
- isAccountNonLocked(): 계정 잠금 여부.
- isCredentialsNonExpired(): 자격 증명 만료 여부.
- isEnabled(): 계정 활성화 여부.
'개발기술 > 보안' 카테고리의 다른 글
네트워크 접근제어(NAC) ; NAT, 방화벽 (0) | 2025.02.25 |
---|---|
보안의 개념과 기술 (0) | 2025.01.19 |
HTTPS 의 TLS 동작과정 (0) | 2025.01.18 |
Security JWT,세션, 쿠키방식 (0) | 2025.01.15 |
Spring Security - JWT 인증방식 구현 (0) | 2024.09.03 |