Web Application이나 API에서 인증(Authentication)과 인가(Authorization) 과정에서 사용되며 사용자 또는 시스템의 신원과 권한을 증명하고 요청의 유효성을 검증하는 데 사용되는 디지털 문자열.
- Token의 장점
- Token은 서버가 아닌 클라이언트에 저장되어 서버의 부담이 적음
- Cookie는 웹 브라우저에만 존재하기 때문에 모바일 앱 등의 다양한 클라이언트에서 인증 처리 불가
- Token 방식은 Stateless 기반이기 때문에 확장성이 뛰어남
- 인증된 사용자임을 확인하기 위한 고유한 서명을 포함하여 위조된 요청인지 확인 가능
- Token의 단점
- Cookie/Session 방식보다 많은 데이터 용량
- 요청이 많아질 시, 트래픽 증가
- Payload(전송되는 데이터)는 암호화되지 않아서 중요한 데이터를 담기에 어려움
- Token을 탈취당하면 대처하기 어려움
- 만료 시간(기본값 : 30분)을 설정
- Token의 동작 순서
- Token 생성 시 사용자의 고유한 정보 포함
- 데이터베이스에 접근하지 않고 Token의 유효성만 검증
![]()
인증에 필요한 정보들을 암호화시킨 JSON 형태의 Token을 의미. JSON 데이터 포맷을 사용하여 정보를 효율적으로 저장하고 암호화로 서버의 보안성 향상.
- JWT Encoding / Decoding
- JWT 구조
XXXXXX.YYYYYY.ZZZZZZ (Header).(Payload).(Signature)
- Header
- 토큰의 타입과 해싱 알고리즘 정의
{ "alg": "HS256", "typ": "JWT" }
- Payload
- 실제로 인증과 관련된 데이터(Claims) 포함
- Claims의 종료
- Registered Claims : 미리 정의된 Claims
- iss(issuer) : 발행자
- exp(expiration time) : 만료시간
- sub(subject) : 제목
- iat(issued At) : 발행 시간
- jti(JWT ID) : 토큰의 고유 식별자
- Public Claims : 사용자가 정의할 수 있는 Claims이며, 공개용 정보 전달이 목적
- Private Claims : 사용자 지정 Claims, 당사자들 간의 정보를 공유하기 위한 목적
{ "sub": "1234567890", "name": "Sparta", "exp": 1682563600 }
- Signature
- Header와 Payload를 서버의
Secret Key
로 서명하여 암호화- 암호화는 Header에서 정의한 알고리즘을 활용
- 서버는 서명을 통해 Token의 변조 여부를 확인 가능
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret )
💡 base64UrlEncode는 URL에서 사용할 수 있도록
+
,/
값을 각각-
,_
로 표기💡 Header와 Payload는 Encoding된 값이기 때문에 복호화 혹은 값을 수정할 수 있지만 Signature는 서버에서 관리하는 값이기 때문에 Secret Key가 유출되지 않는 이상 복호화 불가능
JWT는 Base64로 인코딩되어 쉽게 복호화 할 수 있고, Payload가 그대로 노출되기 때문에 비밀번호나 민감한 정보를 저장하지 않음.
- JWT 인증 과정
- 클라이언트의 로그인 요청
- 로그인에 성공하면 Signature 생성
- 이후 Base64로 Encoding 실행
- 일반적으로 Cookie에 담아서 클라이언트에게 발급
- 서버에 요청을 보낼 때
Authorization
Header에 발급 받은 JWT를 포함- 서버에서 JWT의 유효성 검사를 통과하면 요청 처리
- JWT 만료, 위변조 여부 검사
![]()
- JWT의 유효성 검사
- A의 JWT를 B가 탈취
- B가 탈취한 JWT를 임의로 수정
- B가 수정한 JWT로 Server에 요청
- 서버는 Signature를 사용하여 유효성 검사
- Header, Payload, 서버의 Secret Key값으로 만든 Signature와 비교하기 때문에 조작된 데이터 판별 가능
![]()
💡 JWT의 목적은 정보 보호가 아닌, 위조 방지
- JWT 장점
- Signature로 서버의 보안성 증가
- Token에 필요한 정보(유저 및 검증 정보)가 모두 존재
- 서버는 인증 정보와 관련된 별도의 저장소를 사용하지 않음
- 서버의 수평 확장성(Scale Out) 증가
- Cookie가 없는 다른 환경에서도 인증/인가 적용 가능
- DB를 조회하지 않아도 됨
- JWT 단점
- Payload는 암호화 되어 있지 않기 때문에 민감한 정보를 다루지 못함
- Token의 길이가 길어서 트래픽이 증가하면 네트워크 부하가 증가함
- 클라이언트 측에서 Token을 관리하기 때문에 탈취당하면 대처가 힘듦
Token은 클라이언트에서 관리하여 탈취당할 위험성이 높기 때문에 만료 시간 설정이 필요. 이 때 발생하는 단점을 극복하기 위해 Access Token과 Refresh Token 사용.
- Access Token
- 사용자 인증 후 서버가 발급하는 유저 정보가 담긴 토큰
- 유효 기간 동안 API나 리소스에 접근할 때 사용
- 보안을 위해 짧은 수명을 가짐
- Refresh Token
- Access Token이 만료된 경우 재발급 받기위해 사용
- 주로 데이터베이스에 유저 정보와 같이 저장
- Access Token, Refresh Token 인증
- 클라이언트의 로그인 요청
- 로그인에 성공하면 Signature 생성
- 서버에 요청할 때
Authorization
Header에 JWT(Access Token
)를 포함- 서버에서 JWT의 유효성 검사를 통과하면 요청 처리
Access Token
이 만료 되었다면Refresh Token
으로 토큰 재발급 요청- 서버로부터
Access Token
을 재발급 실행![]()
💡 JWT를 Access Token만을 사용하여 인증한다면 탈취되었을 때 보안에 취약. 유효 시간을 부여하여 문제를 해결하지만 유효 시간이 짧은 경우, 로그인을 자주 해야하기 때문에 Refresh Token 적용.
횡단 관심사라고도 하며 여러 위치에서 공통적으로 사용되는 부가 기능을 의미.
- 핵심 기능(비즈니스 로직)
![]()
- 부가 기능(비즈니스 로직과는 별개로 동작하는 기능)
- Spring AOP 활용 가능
- Web과 관련된 공통 관심사는 Servlet Filter나 Spring Interceptor를 사용
HttpServletRequest
객체를 제공하기 때문에 HTTP 정보나 URL 정보에 접근이 용이💡 AOP(Aspect-Oriented Programmin, 관점 지향 프로그래밍)란?
핵심 관심사(Core Concerns)와 횡단 관심사(Cross-cutting Concerns)를 분리하여 가독성과 모듈성을 증진시킬 수 있는 프로그래밍 패러다임
Servlet Filter는 보안, 로깅, 인코딩, 인증/인가 등 다양한 작업을 처리하기 위해 사용.
- Servlet Filter 특징
- 공통 관심사 로직 처리
- 공통된 로직을 중앙 집중적으로 구현하여 재사용성이 높고 유지보수가 쉬움
- 모든 요청이 하나의 입구를 통해 처리되어 일관성 유지
- HTTP 요청 및 응답 필터링
- Filter Chain
- 여러 개의 필터를 순차적으로 적용 가능
- doFilter()
- 실제 필터링 작업을 수행하는 주요 메소드
- 다음 필터로 제어를 넘길지 결정
- Servlet Filter 적용
- Filter를 적용하면 Servlet이 호출되기 이전에 항상 Filter를 거치게 됨
- 공통 관심사를 필터에만 적용하면 모든 요청 / 응답에 적용됨
- 특정 URL Pattern에 적용 가능
- Spring에서 Servlet은
Dispatcher Servlet
을 의미- 필터를 통과하지 못하면 컨트롤러를 호출하지 않음
![]()
- Filter Chain
- Filter는 Chain 형식으로 구성
- 개발자가 자유롭게 추가할 수 있으며, 순서도 지정 가능
![]()
Java Servlet에서 HTTP 요청과 응답을 가로채고, 이를 기반으로 다양한 처리 작업을 수행하는 데 사용되는 인터페이스.
- jakarta.servlet.Filter
- Filter Interface를 Implements하여 구현하고 Bean으로 등록하여 사용
- Servlet Container가 Filter를 Singleton 객체로 생성 및 관리
- 주요 메소드
init()
- 필터를 초기화하며, Servlet Container가 생성될 때 호출
default
메소드이기 때문에 구현하지 않아도 됨doFilter()
- 클라이언트에서 요청이 올 때 마다 호출
doFilter()
내부에 필터 로직(공통 관심사 로직)을 구현- WAS에서
doFilter()
를 호출해주고 하나의 필터의doFilter()
가 통과된다면, 필터 체인의 순서에 따라서doFilter()
를 호출- 더이상 호출할 필터가 없으면 Servlet 호출
destroy()
- 필터를 종료하는 메소드로서 Servlet Container가 종료될 때 호출
default
메소드이기 때문에 구현하지 않아도 됨💡
ServletRequest
는 기능이 별로 없기 때문에 대부분 기능이 많은HttpServletRequest
를 다운 캐스팅하여 사용