Spring Security?
- Spring 기반의 웹 애플리케이션의 웹 보안 제어를 위한 프레임워크
- 인증 및 권한 부여를 통해 요청에 대한
Resource
제어
JWT (JSON Web Token)
최근 Spring F/W 활용한 웹 애플리케이션에서는 API
유효성 검증을 위한 방식으로,
Token
인증 방식 중에서 JWT
토큰 인증을 많이 사용하고 있다.
JWT Token 공식 스펙 : RFC 7519
특징
JSON
형식의 데이터를 검증하기 위한 토큰 역할- 웹 표준 기반 (RFC 7519) 의 다양한 환경 지원이 가능
- Self-Contained (자가 수용적) 으로서 JWT 자체가 모든 정보를 포함
- 자가 수용적인 특성을 이용해 전달 방식이 비교적 간편(Header 포함 or URL param 전달 가능)
JSON
형식의 인증 정보를 쉽게 추가하는 등 높은 확장성 보장Stateless 무상태
의 서버 구현을 위한 수단으로 사용Signature 서명
정보를 통해 위조 & 변조 방지 가능 (하지만,CSRF
공격 취약)
CSRF Cross-Site Request Forgery
공격
- 공격자가 피해자의 의도하지 않은 작업을 수행하도록 유도하는 해킹 공격
- 공격자가 피해자의
JWT
토큰을 탈취하고 활용 가능
JWT Token 생성 방식
JWT 토큰을 검증하는 방식으로 JWT 인터페이스를 JWS
& JWE
방식으로 구현할 수 있다.
JWS JSON Web Signature
- 서버에서 인증을 근거로 만든 정보를 서버의
Private Key
로 서명하여 Token 정보 생성하는 방식
JWE JSON Web Encryption
- 서버와 클라이언트 간 암호화된 데이터를 Token 정보 생성하는 방식
JWT의 구조
[Header].[Payload].[Signature]
구분 | 역할 |
---|---|
Header | Token 생성 사용된 알고리즘, 토큰 종류 정보 포함 |
Payload | 인증 정보 및 기타 Claim 클레임 정보 포함 |
Signature | Header & Payload 정보를 서명한 정보 포함 |
Header
Payload
- Payload 부분은 Token에 담을 정보(Claim)들을 포함
- Registerd(등록된) Claim : 이미 정해져있는 Token 정보
- Public(공개) Claim : 충돌 방지된(Collision-Resistant) 이름 형식인 URL 형식을 자기고 있는 정보
- Private(비공개) Claim : Registerd 나 Public 이 아닌 정보(충돌 가능)
Signature
- Header 와 Payload 값을 인코딩한 후 결합하여, 비밀키로 Hash하여 생성한 값
Spring Security + JWT 토큰 인증 방식 구현
JwtTokenProvider
- JWT Token 생성 및 유효성 검증을 위한 Component 역할
JwtAuthenticationFilter
- 요청으로 들어온 Token의 유효성 인증을 위한 Filter 역할
- Security 설정 시, UsernamePasswordAuthenticationFilter 앞에 설정
SecurityConfiguration
- 서버의 보안 설정을 하는 Configuration 역할
Resource 접근 제한 표현식
표현식 | 의미 |
---|---|
hasIpAddress | IP주소가 매칭할 경우 |
hasRole | 역할이 부여한 권한과 일치한 경우 |
hasAnyRole | 부여된 역할 중 일치한 항목이 있는 경우 |
permitAll | 모든 접근 승인 |
denyAll | 모든 접근 거부 |
anonymous | 익명의 사용자인지 확인 |
authenticated | 인증된 사용자인지 확인 |
rememberMe | 사용자가 ‘remember me’ 사용해 인증인지 확인 |
fullyAuthenticated | 사용자가 모든 Credential 갖춘 상태에서 인증했는지 확인 |
User Service 구현
Custom UserDetailsService
- UserDetailsService class 재정의
User Entity
- UserDetails class 상속 받아 추가 정보 재정의
User JPA Repository
- findByUid method 추가
SignController
- 인증 성공시, 결과로 JWT token 발급
- 비밀번호 encoding 을 위해 PasswordEncoder 설정(기본 설정은 bcrypt encoding 사용) (Main Application class 에 PasswordEncoder Bean 추가)
Swagger Header Field 추가
추가
예외 처리 보완
예외 상황
- JWT token 없이 API 요청한 경우 - 403 Access Denied 에러
- 형식에 맞지 않거나 만료된 JWT token 으로 API 요청한 경우 - 403 Access Denied 에러
- 유효한 JWT token 이지만, 권한이 없는 경우 - 403 Forbidden 에러
403 Access Denied 예외 처리
- token 검증 단계에서 인증 처리가 불가능하기 때문에 끝나버리는 현상
- Spring Security 에서 제공하는 AuthenticationEntryPoint 를 상속 받아 redirect 처리
403 Forbidden 예외 처리
- token 는 정상이지만 리소스에 대한 권한이 없는 경우
- Spring Security 에서 제공하는 AccessDeniedHandler 를 상속 받아 redirect 처리
Spring Security 관련 기타 Class 및 Interface
UserDetails Interface
- Spring Security 에서 사용자의 정보를 담는 Interface
- User Entity 를 UserDetails 상속을 받아 구현
UserDetailsService Interface
- DB 에서 사용자 정보를 조회하는 Interface
- loadUserByUsername() method 를 통해 UserDetails 형으로 사용자 정보를 저장
SimpleGrantedAuthority Class
- Spring Security 에서 제공하는 권한 관리 Class
- 권한 명칭만 저장하는 구조로 설계
PasswordEncoder Class
- 단방향으로 변환하여 Password 를 안전하게 DB에 저장할 수 있는 Interface