일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- diary
- #내일배움캠프
- KPT
- 변수의 다양성
- Git
- 객체지향 언어
- static
- 메서드
- 인스턴스
- 내일배움캠프
- 포맷은 최후의 보루
- #스파르타내일배움캠프
- Java의 이점
- TiL_1st_0419
- 스파르타내일배움캠프
- Github_token
- 스레드
- JVM
- 성장기록
- GitHub
- 생성자
- 클래스
- Java
- 스파르타내일배움캠프TIL
- 해우소
- 회고록
- Diary 해우소
- Token
- 감사기록
- #스파르타내일배움캠프TIL
- Today
- Total
몬그로이
[인증/인가] 쿠키세션 방식과 JWT 방식 본문
한 서버에서 데이터를 받기 위해서는 인증과 인가를 거치도록 하는 경우가 있다
인증(Authentication) / 인가(Authorization) 의 차이는?
인증은 해당 서버를 이용하기 위해 회원으로 등록한 유저임을 확인받는 것
인가는 인증된 유저가 데이터를 사용할 수 있도록 허가하는 것
얼핏 보기에 서버와 유저가 데이터를 주고 받기 때문에 연결이 된 것으로 인식이 되어지지만
사실은 쿠키세션 방식이나 JWT 방식을 통해서 Connection Statless 를 유지하고 있다
*Statless 는 유저의 정보를 서버가 계속해서 가지고 있지 않는 상태
그렇다면 쿠키세션 방식과 JWT 방식이 무엇이길래
연결을 유지하지 않고도 데이터를 주고받도록 인증과 인가를 거치도록 할 수 있는 것일까?
*JWT = JSON Web Token
쿠키-세션 방식
유저가 처음 회원가입을 진행 한 후 로그인을 한다
- 로그인을 요청하면 서버에서는 DB에서 요청한 유저를 찾아 회원임을 확인하고, 세션을 발급해준다
- 그와 동시에 세션 저장소에 해당 세션을 저장하도록 하며,
- 세션을 받은 유저는 원하는 데이터를 요청할 때마다 쿠키에 해당 세션을 담아 보낸다
- 서버에서는 전달받은 쿠키에서 담겨있는 세션을 찾은다음
- 세션 저장소에 일치하는 세션이 있는지 확인한다
- 확인이 될 경우 원하는 데이터를 제공한다
JWT 방식
유저가 처음 회원가입을 진행한 후 로그인을 요청 한다(인증 요청)
- 로그인을 요청하면 서버에서는 DB에서 요청한 유저를 찾아 회원임을 확인하고, JWT를 발급해 준다(인증)
- 이 때 서버는 JWT를 보관하지 않는다 ***
- 유저는 받은 JWT를 저장소에 보관하며
- 데이터를 요청할 때마다 저장했던 JWT를 함께 보낸다
- JWT 를 따로 저장하지 않기 때문에 "검증"이라는 절차를 거친다
- 검증이 되면 유저가 원하는 데이터를 내어준다 (인가)
(JWT 방식을 이용하기까지)
쿠키-세션 방식을 최대한으로 사용한 방법들
서버가 한 대인 경우라면 세션 저장소가 하나여도 문제가 없으나,
여러가지 문제로 서버가 한 대만 사용하는 경우가 없다고 생각하고 아래의 방법에 대해 이해해 보자
*위에서 유저라고 칭한 것을 클라이언트로 변경함
- 클라이언트가 여럿 들어오는 경우, 한 서버보다 여러 서버에서 각각 나눠서 받는 것이 효율적일 것이다
- 그렇기 때문에 각 서버에서 각 클라이언트의 인증과 인가를 처리하는데,
- 각 서버가 각각 세션 저장소를 가지고 있다면?
- 인증을 받았던 클라이언트가 인가를 받을 때도 항상 그 서버에 요청을 해야만 다시 인증을 받을 필요가 없어질 것이다
- 그렇다면 과연 효율이 좋을 수 있을까?
- 그렇지 못하기 때문에 요청이 들어오는대로 클라이언트의 요청을 받게 되는데, 각각 세션 저장소를 가지고 있다고 가정했기 때문에, 들어온 클라이언트의 요청을 처리하기 위해서 새로 인증을 거쳐야만 하는 이상한 상황이 계속 될 것이다
*로드 밸런서가 클라이언트들을 서버에 분담시키지만 여기서는 생략함
이를 해결하기 위한 방법
첫 번째 - 세션 저장소를 모든 서버에서 공유하는 방법
두 번째 - JWT를 사용하는 방법
첫 번째 방법은 세션 저장소에서 단순히 일치하는 정보를 찾으면되지만
두 번째 방법은 (따로 데이터를 저장하는 형태가 아니기 때문에) JWT를 검증하기 위한 동일한 Key 가 존재해야 한다
이를 Secret Key 라고 부른다
JWT 를 이용하는 절차(흐름, 알고리즘)
- 클라이언트 로그인 성공
- "로그인 정보" 를 (Secret Key로 암호화 하여) JWT 생성
- 생성한 JWT 를 직접 생성한 쿠키에 담아 클라이언트에 전달
* 전달 방법은 개발자가 정하며 **전달하는 위치는 정해져 있음
- 전달받은 JWT를 데이터 요청시마다 함께 보내옴
- 서버에서는 보내온 쿠키에 들어있는 JWT를 찾아서
- JWT를 Secret Key로 디코딩하여 확인함 (1. 위조여부, 2. 유효기간)
JWT 이용 장점
- 사용량이 많은 경우 과부하 방지
JWT 이용 단점
- 복잡한 로직
- secret 키를 탈취당할 경우 jwt 조작 가능
JWT의 구성(디코딩했을 때 얻는 정보: Header, Payload, Verify Signature)
part 1. Header ("alg", "typ")
* typ 은 보통 HMAC SHA256 혹은 RSA 사용
part 2. Payload ( jwt 전자서명의 메타데이터)
클레임을 담고 있는데, 분류하면 registered claim 와 custom claim 으로 나눌 수 있음
* registered claim 는 예약된 형식이 존재
- iss (issuer): Issuer of the JWT
- sub (subject): Subject of the JWT (the user)
- aud (audience): Recipient for which the JWT is intended
- exp (expiration time): Time after which the JWT expires
- nbf (not before time): Time before which the JWT must not be accepted for processing
- iat (issued at time): Time at which the JWT was issued; can be used to determine age of the JWT
- jti (JWT ID): Unique identifier; can be used to prevent the JWT from being replayed (allows a token to be used only once)
7개의 명세가 존재하며 필요에 따라 jwt 의 payload 에 추가하면 됨
** custom claim 은 예약된 형식의 클레임이 아닌 인증 절차의 특성에 따라 커스텀하게 추가할 수 있는 클레임
part3. Verify Signature( 헤더와 페이로드를 암호화한 결과)
Git bash 프로그램을 실행하여
openssl rand -base64 64
를 입력하면 JWT_SECRET_KEY 를 얻을 수 있음
복사 Ctrl + insert
붙여넣기 Shift + insert
JWT를 위한 대표적인 라이브러리는 jjwt와 java JWT가 있는데 JAVA 진영에서 jjwt가 더 많이 사용되고 있음
클래스 분류
- JWT 정의하기 (JWT 생성과 소멸, 가져오기, 확인하기 >> 토큰을 통한 사용자 정보 얻기)
- JwtAuthenticationFilter 설정하기 (클라이언트가 로그인시 사용, 정의된 JWT 를 생성하는 과정에 넣음)
- JwtAuthorizationFilter 설정하기 (클라이언트가 데이터 요청시 사용, 쿠키에서 JWT를 가져와서 확인할 때 정의된 JWT를 넣음)
- SecurityConfig 설정하기 (Security >> AuthenticationFilter >> AuthorizationFilter 순서도 설정해야 하므로 4번째)
참고
* 전달 방법은 개발자가 정하며 **전달하는 위치는 정해져 있음
JWT의 구성(디코딩했을 때 얻는 정보)
https://westlife0615.tistory.com/111