Spring Seucirty
Spring 웹 애플리케이션에서 인증 과 인가를 관리하는 보안 프레임워크이다.

Filter
인증 토큰을 검증하여 사용자 신원을 확인.
- 톰켓에서 dispatcher servlet으로 전달하기 전에 실행
- 요청과 응답에 대해 특정 작업을 수행 후 원래 요청을 서블릿이나 리소스로 전달하는 역할.
- 인증, 로깅, 보안 검사 등에 사용된다.
예시 : JWT 토큰 파싱 및 검증.
FilterChainProxy: Spring Security에서 필터 체인을 관리하는 클래스
- SecurityFilterChain 인터페이스를 통해 요청을 필터링할 필터 목록을 제공.
- Servlet의 기본 Filter 인터페이스를 기반으로 동작.
Interceptor
요청한 사용자의 권한(Role)을 검증하여 특정 리소스 접근 제한.
- DisPatcher Servlet 에서 컨트롤러로 전달하기 전에 실행
- 핸들러 매핑 이후 컨트롤러에 접근하기 전에 인증/인가 처리 가능
- 주로 요청 데이터 검사나 로직 검증에 활용된다.
예시 : 관리자만 접근 가능한 URL 제어.
인증
사용자 또는 시스템의 신원을 확인하는 과정.
사용자가 자신이 주장하는 신원, 즉 자신이 실제로 누구인지를 증명하도록 요구하는 과정이다.
Spring Security에서 인증 과정은 사용자가 제공하는 자격 증명, 보통 사용자 이름과 비밀번호를 기반으로 이루어진다.
Spring Security는 다양한 인증 방식(폼 로그인, OAuth2, JWT 등)을 지원.
인가
인증된 사용자가 특정 자원에 접근할 권한이 있는지를 결정 URL 기반 접근 제어, 메소드 수준 보안, 역할(Role) 기반 권한 부여 등을 통해 세부적인 권한 관리 가능.
SecurityContextHolder
인증 정보를 저장하고 접근하는 클래스 현재 요청의 SecurityContext를 관리하여 인증된 사용자 정보를 저장.
SecurityContext는 또한 인증(Authentication) 정보를 담고 있는 인터페이스이다. SecurityContext는 인증 정보를 Authentication 객체로서 저장하고, Authentication 객체는 사용자의 인증 상태와 권한 정보를 담고 있으며, 이를 통해 사용자가 어떤 권한을 가지고 있는지, 그리고 현재 인증된 사용자에 대한 세부 정보를 알 수 있게 되는 것
ex) SecurityContextHolder.getContext().getAuthentication()을 통해 인증 정보에 접근 가능.
SecurityContext
- SecurityContext는 현재 인증된 사용자의 정보를 담고 있는 인터페이스.
- 사용자가 어플리케이션에 로그인하면, 해당 사용자의 인증 정보가 Authentication 객체로 생성되고, 이 객체는 SecurityContext에 저장
- 이후 애플리케이션의 어디에서든 SecurityContext를 통해 현재 사용자의 인증 정보에 접근할 수 있다.
- 인증 상태와 권한 정보를 기반으로 보안 결정을 내리는 데 사용.
Authentication
- 사용자의 인증 및 권한 정보를 표현하는 인터페이스
- 주요 구성 요소:
- Principal: 사용자의 식별자를 의미. → UserDetail or 사용자명을 나타내는 String 등.
- Credentials: 인증 자격(예: 비밀번호).
- Authorities: getAuthorities() 메서드를 통해 접근할 수 있으며, 사용자가 가지고 있는 권한(또는 역할)의 목록을 제공. 이 권한들은 GrantedAuthority 인터페이스의 구현체로 표현
- Authenticated: isAuthenticated() 메서드를 통해 현재 사용자가 인증되었는지 여부를 반환. 인증이 성공적으로 이루어진 경우, 이 값은 true
UserDetails
- 사용자 정보를 캡슐화하는 인터페이스.
- 커스텀 구현 시 사용자 이름, 비밀번호, 권한, 계정 상태(활성화, 잠김 여부 등)를 정의.
- Spring Security는 이를 통해 인증 가능한 사용자 정보를 관리.
어플리케이션에서 추가적인 사용자 정보를 관리하거나 특수한 로직이 필요한 경우, UserDetails 인터페이스를 구현하여 커스텀할 수 있다.
커스텀 할 때 기본적으로 오버라이드 해야하는 메소드는 다음과 같다.
< 표 1 > UserDetails 메서드
메소드 반환 타입 설명 기본값
| getAuthorities() | Collection<? extends GrantedAuthority> | 사용자 권한 목록을 반환 | |
| getPassword() | String | 사용자 비밀번호를 반환 | |
| getUsername() | String | 사용자 고유한 값을 반환 | |
| isAccountNonExpired() | boolean | 계정의 만료 여부 반환 | true ( 만료 안됨 ) |
| isAccountNonLocked() | boolean | 계정의 잠김 여부 반환 | true ( 잠기지 않음 ) |
| isCredentialsNonExpired() | boolean | 비밀번호 만료 여부 반환 | true ( 만료 안됨 ) |
| isEnabled() | boolean | 계정의 활성화 여부 반환 | true ( 활성화 됨 ) |
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
public class CustomUserDetails implements UserDetails {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
@Override
public String getPassword() {
return null;
}
@Override
public String getUsername() {
return null;
}
@Override
public boolean isAccountNonExpired() {
return UserDetails.super.isAccountNonExpired();
}
@Override
public boolean isAccountNonLocked() {
return UserDetails.super.isAccountNonLocked();
}
@Override
public boolean isCredentialsNonExpired() {
return UserDetails.super.isCredentialsNonExpired();
}
@Override
public boolean isEnabled() {
return UserDetails.super.isEnabled();
}
}
UserDetailsService
UserDetailsService는 사용자명(username)을 기반으로 UserDetails 객체를 로드하는 역할
사용자 인증 과정에서 필요한 사용자 정보를 데이터베이스나 다른 저장소에서 가져오는 데 사용된다.
메소드 반환 타입 설명
| loadUserByUsername() | UserDetails | 유저의 정보를 불러와서 UserDetails로 반환 |
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
public class CustomUserDetailService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return null;
}
}
Security Config
어플리케이션의 보안 정책을 종합적으로 정의하고 관리하는 중심적 구성 요소
Spring Security를 활용하는 애플리케이션에서 반드시 필요하며 다음과 같은 설정을 할 수 있다.
- 인증(Authentication) 관리
- SecurityConfig는 사용자 인증을 위한 설정을 담당한다. - 사용자 정보의 출처를 정의하는 UserDetailsService, 비밀번호 암호화 방식, 인증 요청 처리 방식을 설정하는 작업이 포함된다
- 이 과정에서 개발자는 데이터베이스, LDAP, OAuth2 등 다양한 인증 방법을 선택하고 구현할 수 있다.
- 권한 부여(Authorization) 관리 사용자가 애플리케이션 내의 자원에 접근할 수 있는지 여부를 결정하는 과정 URL 기반 접근 제어와 메소드 기반 접근 제어를 설정하여, 특정 역할(Role)이나 권한(Authority)을 가진 사용자만이 특정 자원에 접근할 수 있도록 보장한다. 이를 통해 민감한 정보나 기능에 대한 비인가 접근을 방지
- HTTP 보안 설정 CSRF보호 , 세션 관리 등 웹 애플리케이션의 보안과 관련된 다양한 HTTP 설정을 제공
- 커스터마이징과 확장 개발자는 자신만의 인증 방식이나 필터를 추가하거나, 기존의 보안 흐름을 재정의하여 애플리케이션의 보안 모델을 더욱 견고하게 만들 수 있다.
Form
form 로그인 방식은 사용자가 로그인 정보를 제공하여 이를 바탕으로 사용자의 신원을 확인하여 인증하는 방식이다. 주로 POST 요청을 통해 서버로 전송된 사용자 입력값을 서버에서 처리하게 된다. Spring Security는 이러한 로그인 폼을 매우 쉽게 설정하고 관리할 수 있는 기능을 제공.
과정은 다음과 같다
- 사용자가 아이디 비밀번호 입력
- http요청을 통해 전달받아 Spring security는 요청을 UsernamePasswordAuthenticationFilter를 통해 처리.
// 내일 예제코드 보고 수정
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin() // Form 기반 로그인 활성화
.loginPage("/login") // 커스텀 로그인 페이지 URL
.defaultSuccessUrl("/home", true) // 로그인 성공 시 이동할 URL
.permitAll() // 모든 사용자 접근 허용
.and()
.logout() // 로그아웃 설정
.logoutSuccessUrl("/login?logout") // 로그아웃 성공 후 이동할 URL
.permitAll();
}
- UsernamePasswordAuthenticationFilter 처리:
- 입력값을 UsernamePasswordAuthenticationToken 객체로 변환.
- 이 객체는 인증되지 않은 상태로 생성됩니다.
- AuthenticationManager로 인증 요청 전달
- 여러 AuthenticationProvider를 순회하여 적합한 인증 제공자가 있는지 확인.
- 보통 DaoAuthenticationProvider가 UserDetailsService를 통해 사용자 정보를 조회.
- 비밀번호 검증
- PasswordEncoder를 사용하여 입력된 비밀번호와 저장된 암호화된 비밀번호를 비교.
- 일치하면 인증 성공.
@Bean
public AuthenticationManager authManager(HttpSecurity http) throws Exception {
return http.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(customUserDetailsService) // 사용자 정보 조회 서비스
.passwordEncoder(passwordEncoder()) // 비밀번호 인코딩
.and()
.build();
}
Granted Authority 객체를 이용해 인가를 저장
인가 : 인증의 마지막 프로세스에서 관리되는 것
인코딩 , 디코딩
인코딩
- 주로 비밀번호를 안전하게 처리하는데 사용된다.
- 사용자로 부터 입력받은 비밀번호를 주로 해시함수를 사용하여 변환한 후 사용하는 방식이다.
- 인코딩은 단방향으로 암호화하여 db 유출 시에도 사용자의 비밀번호가 보호되도록 한다.
- Spring Security는 여러 인코딩 알고리즘을 제공하는데 대표적으로 BCryptPasswordEncoder가 사용됨. → 이 알고리즘은 해시화하고 추가적으로 Salt를 적용하여 같은 비밀번호라도 다른 해시값을 생성하도록 한다. 저장하는 시점에 매번 다른 Salt가 생겨 Salt도 함께 저장되는 것 디코딩할 때는 저장된 Salt도 가져와서 해시화 하여 인증. 디코딩할때도 Salt로 다른 해시값으로 인증하는게 아님.
디코딩
- 데이터를 원래 상태로 복원하기보다는 주로 검증하는 역할을 수행한다.
- 사용자가 입력한 비밀번호를 저장된 인코딩된 비밀번호와 비교하여 해시값과 일치하는지 확인하여 인증한다.
세션
- 세션은 서버가 관리하는 사용자의 정보이다 : 사용자의 로그인상태를 유지중
- 서버측에서 세션이 생성될 때 만들어진 세션ID로 식별한다.
- 사용자 정보는 서버에 저장되고, 브라우저에는 세션ID만 있음.
- 세션은 일정 시간 동안만 유지됨(ex 30분). 시간이 지나면 만료되 로그아웃 처리
쿠키
- 쿠키는 HTTP 프로토콜의 stateless(상태 비저장) 특성을 보완하기 위한 기술.
- 클라이언트(브라우저)가 관리하는 정보이다. ex) 사용자의 다크모드 설정, 선호 설정, 로그인 정보
- 쿠키가 탈취되거나 변조되면 보안 문제가 생길 수 있음. 이를 막기 위해 httpOnly, Secure 과 같은 옵션을 사용
Security의 Thymeleaf
Spring Security와 Thymeleaf는 HTML 템플릿에서 인증 및 권한을 쉽게 처리할 수 있도록 돕는 속성을 제공한다.
- sec:authorize
- 특정 권한에 따라 콘텐츠를 표시하거나 숨김.
- 예: sec:authorize="isAuthenticated()" → 로그인한 사용자만 볼 수 있음.
isAnonymous() 비로그인 사용자에게만 콘텐츠 표시 isAuthenticated() 로그인된 사용자에게만 콘텐츠 표시 hasRole('ROLE_NAME') 특정 권한을 가진 사용자만 콘텐츠 표시 hasAnyRole('ROLE1', 'ROLE2') 여러 권한 중 하나를 가진 사용자에게 콘텐츠 표시 permitAll 모든 사용자에게 콘텐츠 표시 denyAll 누구에게도 콘텐츠 표시하지 않음 - sec:authentication
- 인증된 사용자 정보를 템플릿에서 가져온다.
principal 인증된 사용자의 객체 principal.name 인증된 사용자의 사용자명 principal.authorities 인증된 사용자의 권한 목록
1. sec:authorize 예시
HTML 템플릿에서 사용자 권한에 따라 콘텐츠를 표시
<!-- 로그인된 사용자만 보기 -->
<div sec:authorize="isAuthenticated()">
안녕하세요, <span sec:authentication="name"></span>님!
</div>
<!-- 관리자만 접근 가능 -->
<a href="/admin" sec:authorize="hasRole('ADMIN')">관리자 페이지</a>
<!-- 비로그인 사용자만 보기 -->
<div sec:authorize="isAnonymous()">
<a href="/login">로그인</a>
<a href="/signup">회원가입</a>
</div>
<!-- 모든 사용자에게 콘텐츠 노출 -->
<div sec:authorize="permitAll">
모든 사용자가 볼 수 있는 공지사항입니다.
</div>
2. sec:authentication 예시
템플릿에서 로그인된 사용자 정보를 출력.
<!-- 사용자 정보 출력 -->
<p>현재 사용자: <span sec:authentication="name"></span></p>
<!-- 사용자 권한 출력 -->
<p>권한: <span sec:authentication="principal.authorities"></span></p>
CSRF 공격
(Cross-Site Request Forgery) 로그인 되어 있는 인증정보를 가지고 공격하는 것 (쿠키, 세션으로 자주 발생)
공격자가 사용자의 인증 정보를 이용해 악의적인 요청을 보내는 방식으로 이루어진다.
CSRF 공격을 방지하기 위한 주요 방법 중 하나는 CSRF 토큰을 사용하는 것이다.
Spring Security에서 CSRF의 설정
Spring Security를 사용하면 기본적으로 CSRF 보호가 활성화 된다.
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) // CSRF 토큰을 쿠키에 저장
)
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated() // 모든 요청 인증 필요
);
return http.build();
}
}
CORS
Cors(Cross-Origin Resource Sharing)는 원하지 않는 출처에서 서버 리소스가 무단으로 접근되는 것을 방지하기 위한 보안 장치이다. 보안상의 이유로 기본적으로 다른 출처의 리소스에 대한 요청을 차단하는데 이 때문에 다음과 같은 문제가 발생한다. CORS 문제는 일반적으로 클라이언트와 서버가 다른 출처에 있을 때 발생한다. Cors는 두가지 주요 요청 유형을 관리한다.
- 첫번째로 단순 요청 get,post,head와 같은 제한된 헤더를 사용하는 요청으로 Access-Control-Allow-Origin헤더만 포함하여 응답하면 된다.
- 두번째는 프리 플라이트요청(preflight requests)은 OPTIONS 메서드를 사용하여 서버의 정책을 사전에 확인하는 요청으로 요청의 유효성을 검증해 응답한다.
예시 :
- 프론트엔드: http://localhost:3000
- 백엔드: http://localhost:8080
이런 경우:
- 클라이언트가 API 요청을 보내면 브라우저는 CORS 정책을 확인.
- 서버가 해당 요청을 허용하지 않는다면, 브라우저는 요청을 차단하고 CORS 오류를 발생시킨다.
해결 방법은 클라이언트가 다른 출처에서 오는 요청을 처리할 수 있도록 허용하는 것이다.
Spring Security에서 Cors의 설정
@Configuration
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.cors(cors -> {}) // CORS 활성화 (CorsConfigurationSource 사용)
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated() // 모든 요청 인증 필요
);
return http.build();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(List.of("<http://localhost:3000>")); // 허용할 Origin
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE")); // 허용할 HTTP 메서드
configuration.setAllowedHeaders(List.of("Authorization", "Content-Type")); // 허용할 헤더
configuration.setAllowCredentials(true); // 쿠키 허용
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration); // 모든 경로에 적용
return source;
}
}
jwt (JSON Web Token)
JSON 객체를 사용하여 정보를 안전하게 전달하기 위한 토큰 기반 인증 방식이다.
'Spring' 카테고리의 다른 글
| Redis와 사용법 (0) | 2025.06.29 |
|---|---|
| OAuth2.0 google, kakao, naver (1) | 2024.12.02 |
| [오르미 백엔드7기](Spring 프록시객체, 지연로딩 ,즉시로딩, 영속성전이, N+1문제) (1) | 2024.11.25 |
| [오르미 백엔드 7기] (Spring Entity 개념, 연관관계, 공통속성정의) (0) | 2024.11.25 |
| [오르미 백엔드7기] (Spring JPA 기본,ORM이란? , JDBC) (0) | 2024.11.22 |