1. 로그인을 구현하는 법
👎 유저에게 계속 ID와 Password를 요청하는 방식
- 유저에게 ID와 Password를 받아와서 DB와 비교하는 방식이다.
- 로그인 유지가 안되기 때문에 페이지를 이동하면 정보가 유지되지 않는다.
- 보안에도 취약하다.
👎 Session 방식 (서버 유지 방식)
서버의 메모리, DB와 같은 서버의 자원을 이용해 사용자의 정보를 유지시키는 방식이다.
작동 시퀀스
장점
단점
- 서버의 확장성이 떨어진다.
- 서버의 자원이 많이 필요하다.(세션을 저장, 유지해야하므로)
- 보통 트래픽의 분산을 위해 여러 대의 서버를 사용하는데, 로그인 시 세션을 참조할 때는 세션이 저장된 해당 서버에만 요청을 보내야 한다.
👍 Token 방식 (클라이언트 유지 방식)
사용자가 로그인을 하면 서버에서 발행해주는 토큰을 브라우저 저장소에 저장해 정보를 유지하는 방식이다.
장점
- 서버에 저장하지 않기 때문에 서버에 확장성이 있다.
- 해당 토큰이 유효한지 체크만 하면 되기 때문에 Session 방식과 달리 어떤 서버로 요청을 보내도 상관이 없다.
2. JWT
JWT는 웹표준(RFC 7519)으로, 전자 서명된 URL-safe(URL로 이용될 수 있는 문자만 구성된)의 JSON이다.
공개키 암호방식을 사용한다.
🔧 JWT 구조
JWT는 .
을 기준으로 세 부분으로 나뉜다.
- 토큰의 타입
- 해시 알고리즘 정보
- 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 Token
과 Refresh Token
을 동시에 보내준다.
단, 둘의 유효기간은 다르게 설정해서 보낸다.
Refresh Token
을 하루, Access Token
을 한 시간으로 잡았다면 Access Token
의 기간이 만료되어도 Refresh Token
의 기간이 남아있기 때문에 사용자는 로그인 없이 다시 Access Token
을 발급 받을 수 있다.
따라서 로그인이 유지된다.
🔧 토큰을 저장하는 위치
는 개발자의 취향과 서비스의 성격에 따라 달라진다.
Local Storage
- 해당 도메인에 영구 저장하고 싶을 때.
- CSRF(Cross-site Request Forgery) 공격에 안전하다.
- XSS(Cross-site Scripting)에 취약하다.
Cookie
- 해당 도메인에 날짜를 설정하고 그 때 까지만 저장하고 싶을 때.
- 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,정확하게 무엇이고 왜 쓰이는 걸까?