JWT는 뭘까
JWT를 알기 전에 인증과 인가가 무엇인지 먼저 간단하게 알아보자.
인증 : Authentication // 인가 : Authorization
계정에 관련돼서 서버를 프로그래밍할 때 인증과 인가를 어떻게 해결할 지 고민해야한다.
- 인증은 쉽게말해 로그인을 얘기한다. 사용자가 웹사이트를 이용할 때 아이디와 비밀번호로 인증을 받는 행위를 얘기할 수 있다.
- 인가는 인증을 한 번 받은 사용자가 이후 여러 서비스를 사용할 때 사용자의 계정으로만 할 수 있는 활동을 시도할 때 로그인이 되어있음을 알려주고 허가를 해주는 행위.
그래서 JWT가 뭔데?
- JWT는 위에서 설명한 인가에 관련된 기술이다.
- JWT (JSON Web Token)는 인터넷에서 정보를 안전하게 전달하기 위한 인증 방식 중 하나이고, JSON 형식으로 인코딩된 토큰으로, 사용자 인증 정보를 포함하고 있다.
JWT vs Session
Session
💡 session과 token이 필요한 이유를 먼저 설명 하겠다. http 웹사이트를 이용할 때 프로토콜은 Stateless이다.
Stateless란 서버로 가는 모든 요청이 이전 요청과 독립적으로 다뤄진다는 뜻이다. 그 말은 즉 요청이 끝나면 서버는 사용자가 누군지 잊어버리는 된다는 것이다. 그래서 사용자는 요청을 할 때마다 사용자의 정보를 서버에게 알려줘야한다.
이것을 하는 방법 중 하나가 Session이다.
Session 인증방식
Alice라는 사용자가 웹사이트에 로그인을 하기 위한 과정으로 다시 설명해보겠다.
- Alice는 UserID와 password를 서버에 보낸다.
- UserId와 password가 일치하다면 서버는 Alice의 정보를 session DB(Session store)에 생성할 것이다. 해당 session DB에는 별도의 ID가 존재하고, 그 session ID는 쿠키를 통해 브라우저로 들어와 저장된다.
- 로그인이 진행 된 후 Alice가 웹사이트에서 제공하는 서비스들을 이용하기 위해 다른 페이지로 이동한다면, 브라우저는 세션ID를 갖고 있는 쿠키를 서버로 보낼 것이다.
- 이제 서버는 쿠키에 있는 세션ID를 가지고 세션 DB를 확인 하고, 그 이후에 서버는 Alice의 정보를 알 수 있게 된다.
cookie란?
- 웹 서버에서 사용하는 쿠키는 클라이언트(웹 브라우저) 측에 데이터 파일로 저장되는 정보
- 일반적으로 서버에서 클라이언트에게 특정 정보를 저장하거나, 클라이언트의 활동을 추적하는데 사용된다.
- 쿠키에는 이름, 값, 만료 날짜 등의 정보가 포함될 수 있다. 일반적으로 쿠키의 만료 날짜는 클라이언트가 종료될 때까지 혹은 일정 시간이 지난 후 에 만료가 된다.
cookie의 생성과정
- Alice라는 사용자가 어떠한 사이트에 방문을 하기 위해 Alice가 사용하는 브라우저는 서버에 요청을(request)를 보냄.
- 서버는 이 요청에 응답(response)를 함.
- 응답에는 필요한 모든 데이터와 브라우저가 요청한 페이지 정보가 있을 것이다. 이 때 데이터에는 브라우저에 저장하고자 하는 쿠키가 같이 들어있음. - 이 때 쿠키는 브라우저에 저장이 되고, 이 후에 브라우저가 서버에 요청을 보낼 때 쿠키와 같이 보내진다.
💡 Session은 어디에 저장이 될까? Session은 서버 메모리에 저장 될 수도 있고, 데이터베이스나 파일 시스템 등에 저장 될 수도 있다. 처음 세션은 아파치 톰캣이 점유중인 메모리 공간 내부에 있는 톰캣의 세션 저장소에 저장을 했다. 메모리의 휘발성 문제를 해결하는 과정에서 데이터베이스까지 사용했다고 한다!
장/단점
장점
- 세션을 사용하면 서버는 로그인 된 유저의 모든 정보를 저장한다. 해당 정보를 이용해 새로운 기능들을 추가 할 수 있는 장점이 있다.
ex)인스타그램의 로그인된 디바이스 종료 / 넷플릭스 계정 공유 숫자 제한 - SessionID만 보내기 때문에 세션의 크기가 커도 네트워크 부하가 거의 없다.
- 서버 용량이 충분할 경우 저장 개수나 용량 제한이 없다.
단점
- Session을 사용하기 위해서는 DB를 사고, 유지해야함, 유저가 늘어남에 따라 DB로 지속적으로 늘려줘야하는 단점을 가지고 있다.
- 웹 브라우저에서 세션 관리에 사용하는 쿠키는 단일 도메인 및 서브 도메인에서만 작동하도록 설계되어 CORS 방식(여러 도메인에 request를 보내는 브라우저)을 사용할 때 쿠키 및 세션 관리가 어렵다.
Session에 대해서 중요하게 생각해야 할 것은 사용자의 정보를 가지고 있는 것은 서버이고, 사용자가 갖고 있는 것은 세션 ID 뿐이라는 것이다.
세션ID는 일반적으로 랜덤한 문자열 형태로 생성되며, HTTP 응답의 Set-Cookie 헤더를 통해 클라이언트에게 전송된다. 예를 들어, 다음과 같은 Set-Cookie 헤더를 가진 HTTP 응답을 받았다면, 이는 서버에서 세션 ID를 생성하여 클라이언트에 전송한 것이다.
Set-Cookie: session_id=abcdefg123456789; Path=/
위의 예제에서는 **session_id**라는 이름으로 **abcdefg123456789**라는 세션 ID가 생성되었으며, 해당 쿠키는 **/**경로에서 유효하다. 클라이언트는 이후 모든 요청에서 이 쿠키를 포함시켜서 서버와의 상호 작용을 수행한다.
JWT
Session은 현재 로그인한 유저들의 모든 세션ID를 DB에 저장하고 있어야 하고, 요청이 들어올 때마다 서버는 쿠키에 있는 세션ID로 유저를 찾은 후에 다음 작업을 진행 할 수 있는 것이다. 즉, Session의 경우 요청이 있을 때마다 DB를 찾아야하고, 유저가 늘어남에 따라 DB 리소스가 더 필요하다는 단점이 존재한다. 반면, JWT는 토큰 형식으로 만들어졌다. JWT로 유저 인증을 처리하면 세션DB를 가지고 있지 않아도 된다. 또한 JWT 방식으로 발급받은 토큰의 경우 Session에서 Sessionid만 발급하는 것과 다르게 많은 정보를 가지고 토큰을 생성한다.
JWT는 “header.payload.signature” 세 부분으로 나뉘어져 있다.
- header 토큰의 타입과 서명 알고리즘 등의 메타데이터 정보를 포함하고 있다
- payload JWT에 저장될 클레임(Claim) 정보를 포함한다. Claim은 JWT에 저장될 데이터의 속성과 값으로 이루어진 Json형식으로 되어 있다. 클레임의 종류는 크게 세 가지로 분류되어 있다.
- 등록된 클레임
- sub: 토큰 제목 (subject)exp: 토큰의 만료시간 (expiraton),iat: 토큰이 발급된 시간 (issued at),
- jti: JWT의 고유 식별자
- 시간의 경우 NumericDate 형식으로 되어있어야하고, 현재 시간 이후로 설정 되어 있어야한다.
- aud: 토큰 대상자 (audience)
- iss: 토큰 발급자 (issuer)
- 공개 클레임
- 충돌이 방지된 이름을 가지고 있어야 한다. 충돌방지를 위해 URI 형식으로 짓는다.
- 비공개 클레임
- 클라이언트와 서버 협의하에 사용되는 클레임 이름이다. 중복되어 충돌이 될 수 있다.
- 등록된 클레임
- signature header와 payload를 조합한 후, 서버에서 비밀키를 사용하여 생성한 서명값이다. 이 것으로 유효성을 검증 할 수 있다.
JWT 인증방식
Session설명과 동일하게 JWT가 Token을 생성하고 인증하는 절차에 대해 알아보겠다.
- Alice는 UserId와 password를 서버에 보낸다. Session과 JWT 둘다 유저가 로그인을 하기 위해 유저ID와 비밀번호를 서버에 보내는 것 까지는 동일하다.
- JWT는 유저명과 비밀번호가 일치한다면 DB에 뭔가를 생성하지 않고, 서버는 유저 ID를 가지고 어떠한 알고리즘을 이용하여 서명된 JWT String 형태로 유저에게 전달한다.
- 이 후에 웹사이트에 요청을 할 때는 발급된 Token을 서버에 보내야한다. 서버는 토큰을 받고, 해당 사인이 유효한지 체크를 한 후 토큰이 유효하다면 유저를 인증해준다.
장 / 단점
장점
- DB를 따로 살 필요가 없다.
- JSON 코드 언어로 생성된 토큰이기 때문에 용량이 작다.
- 쿠키를 사용하지 않아 쿠키를 사용할때 발생하는 취약점이 사라진다.
단점
- Session의 장점인 “세션을 사용하면 서버는 로그인 된 유저의 모든 정보를 저장한다. 해당 정보를 이용해 새로운 기능들을 추가 할 수 있는 장점이 있다.”가 안된다. 즉 토큰을 서버에서 제어를 할 수 없다는 것이다. 혹여나 토큰을 해킹당하더라도 무효화 할 방법이 없다는 것! //토큰은 만료되기 전까지 유효하기 때문.
💡 1번 단점을 보완하기 위해 쓰는 여러가지 방법들이 있는데, 로그인을 할 때 토큰을 2개를 발행한다. 하나는 만료시간이 짧은(보통 몇분, 몇시간) access 토큰과 나머지는 긴 기간(보통 2주)을 가지 refresh 토큰이다. refresh 토큰의 상응값을 데이터베이스에도 저장한다. 사용자의 access토큰이 만료된다면 서버에 refresh 토큰을 보내고, 데이터베이스에 저장된 값과 대조를 해본 맞다면 새로운 access토큰을 발행 해주는 것이다.
- payload 인코딩 : Token의 payload는 암호화된 것이 아니라서 누구나 탈취하여 디코딩하면 데이터를 볼 수 있다는 단점이 있어 중요 데이터를 넣지 않아야 한다.
- 위의 단점을 해결하기 위해 JWE(Json Web Encryption)를 사용하여 payload의 내용을 암호화하면 된다.