[Security] JWT (JSON Web Tokens)

Bik_Kyun·2022년 3월 26일
0
post-thumbnail

1. 로그인을 구현하는 법

👎 유저에게 계속 ID와 Password를 요청하는 방식

  • 유저에게 ID와 Password를 받아와서 DB와 비교하는 방식이다.
  • 로그인 유지가 안되기 때문에 페이지를 이동하면 정보가 유지되지 않는다.
  • 보안에도 취약하다.

👎 Session 방식 (서버 유지 방식)

서버의 메모리, DB와 같은 서버의 자원을 이용해 사용자의 정보를 유지시키는 방식이다.

작동 시퀀스

장점

  • 토큰 방식보다 보안에 강하다.

단점

  • 서버의 확장성이 떨어진다.
  • 서버의 자원이 많이 필요하다.(세션을 저장, 유지해야하므로)
  • 보통 트래픽의 분산을 위해 여러 대의 서버를 사용하는데, 로그인 시 세션을 참조할 때는 세션이 저장된 해당 서버에만 요청을 보내야 한다.

👍 Token 방식 (클라이언트 유지 방식)

사용자가 로그인을 하면 서버에서 발행해주는 토큰을 브라우저 저장소에 저장해 정보를 유지하는 방식이다.

장점

  • 서버에 저장하지 않기 때문에 서버에 확장성이 있다.
  • 해당 토큰이 유효한지 체크만 하면 되기 때문에 Session 방식과 달리 어떤 서버로 요청을 보내도 상관이 없다.

2. JWT

JWT는 웹표준(RFC 7519)으로, 전자 서명된 URL-safe(URL로 이용될 수 있는 문자만 구성된)의 JSON이다.
공개키 암호방식을 사용한다.

🔧 JWT 구조

JWT는 .을 기준으로 세 부분으로 나뉜다.

1) Header

  • 토큰의 타입
  • 해시 알고리즘 정보
  • BASE64 방식으로 인코딩해서 JWT 첫 부분에 기록된다.(암호화가 아니므로 중요정보를 넣으면 안된다.)
{
	'alg' : 'HS256',
    'typ' : JWT'
}

2) Payload

  • 우리가 보내고자 하는 데이터를 담는 곳.
  • Registered Claim : 만료시간을 나타내는 exp와 같이 미리 정의된 집합
  • Public Claim : 공개용 정보 전달
  • Private Claim : 클라이언트와 서버간 협의하에 사용, 사용자의 정보를 유추할 수 없는 정보(PK)를 담는다.
  • 위의 세가지 요소를 조합하여 작성한뒤 BASE64 인코딩하여 두번째 요소에 위치시킨다.(암호화가 아니므로 중요정보를 넣으면 안된다.)
{
	'user-id' : '1',
    'exp' : '1539517391'
}

3) Signature

  • JWT가 원본 그대로라는 것을 확인할 때(무결성을 확인할 때) 사용하는 부분이다.
  • 헤더, 페이로드 그리고 JWT secret을 헤더에 지정된 암호 알고리즘으로 암호화하여 전송한다.(복호화 가능)
  • 프론트엔드가 JWT를 백엔드 API 서버로 전송하면 서버에서는 전달받은 JWT의 서명부분을 복호화하여 서버에서 생성한 JWT가 맞는지 확인한다.
  • BASE64를 통해 인코딩만 한것이므로 중요정보를 넣으면 안된다.

🔧 JWT 수행과정

1) Only "Acces Token"

1~3번 까지의 동작을 수행하면 로그인이 된것이고 인증을 받은 것이다.

4️⃣

클라이언트는 API를 요청할 때 authorization header에 JWT(Access Token)을 담아서 보낸다.

5️⃣

서버는 secret key로 사용자가 보낸 토큰의 서명을 복호화하여 유효한 토큰인지 확인한다.

4~6번 동작을 반복적으로 수행하며 인가를 하는 것이다.

2) With "Refresh Token"

1번의 방식으로 진행했을 때의 문제점은 Access Token을 탈취 당했을 때이다.
(토큰에 user.id만 집어 넣으면 안되는 이유)
토큰의 유효기간이 길 경우, 해당 시간동안 정보가 탈취 당하게 되는데 이를 의식해 유효기간을 줄이면 사용자가 로그인을 여러 번 해야하는 번거로움이 발생한다.
이를 해결하기 위해 Refresh Token을 사용한다.

Refresh Token 또한 Access Token과 같은 JWT이다.
로그인을 하게되면 서버에서 Access TokenRefresh Token을 동시에 보내준다.
단, 둘의 유효기간은 다르게 설정해서 보낸다.

Refresh Token을 하루, Access Token을 한 시간으로 잡았다면 Access Token의 기간이 만료되어도 Refresh Token의 기간이 남아있기 때문에 사용자는 로그인 없이 다시 Access Token을 발급 받을 수 있다.
따라서 로그인이 유지된다.

🔧 토큰을 저장하는 위치

는 개발자의 취향과 서비스의 성격에 따라 달라진다.

Local Storage

  • 해당 도메인에 영구 저장하고 싶을 때.
  • CSRF(Cross-site Request Forgery) 공격에 안전하다.
  • XSS(Cross-site Scripting)에 취약하다.
  • 해당 도메인에 날짜를 설정하고 그 때 까지만 저장하고 싶을 때.
  • XSS(Cross-site Scripting) 공격으로 부터 LocalStorage에 비해 안전하다.
  • XSS(Cross-site Scripting), CSRF(Cross-site Request Forgery) 둘 다 취약해질 수 있다.

👍 쿠키를 사용하여 XSS를 막고 Refresh Token 방식을 이용하여 CSFR를 막을 수 있다.

🔧 JWT의 장단점

장점

  • 별도의 인증 저장소가 필요 없어서 서버와의 통신을 최소한으로 할 수 있다.
  • 트래픽 부담이 적다.
  • JWT라는 독립적인 개체를 사용한다는 것.

단점

  • JWT의 크기가 커질수록 거의 모든 요청에 대해 함께 전송되므로 데이터 트래픽 크기에 영향을 미칠 수 있다.
  • 토큰은 클라이언트에 저장되므로 DB에서 사용자 정보를 수정하더라도 토큰에 직접 적용되지 않는다.

<참고>
JWT는 어디에 저장해야할까? - localStorage vs cookie
JWT,정확하게 무엇이고 왜 쓰이는 걸까?

profile
비진

0개의 댓글