24/06/12 인증, 인가, 쿠키, 토큰, JWT 에 대해
로그인과 회원가입 등의 기능은 보안이 중요하다. 이를 위해, 인증과 인가, 쿠키, 토큰, JWT 에 대해 간단히 알아보자.
인증, 인가란?
- 인증(Authentication)이란 서비스를 이용하려는 유저가
등록된 회원
인지 확인하는 절차 -> 일반적인 로그인 과정 - 인가(Authorization)이란, 인증을 받은 유저가
리소스에 접근할 수 있는 특정 권한
이 있는지 확인하는 절차 -> 로그인 후 접근 가능한 요소 같은 것들
HTTP 의 특징 2가지
우리가 이용하는 웹 사이트의 대부분은 http 를 사용한다. 그 특징을 잠깐 알아보자.
(1). 무상태(stateless): 각 요청은 독립적임. 별도의 처리를 하지 않는다면 서버는 클라이언트가 이전에 어떤 요청을 보냈는지 정보를 기억하지 않음. => 그래서 우리가 서버에 요청을 보낼 때, 헤더를 통해 정보를 담아줘야하는 것.
(2). 비연결성(connectless): 요청과 응답이 이루어지면, 연결이 종료됨. 클라이언트와 서버 간 연결을 지속하지 않음.
이렇게 상태를 저장하지도 않고, 항상 서버와 연결되어있는 것도 아닌데 어떻게 로그인 했는지 아닌지 확인하는 것일까??
이는 앞서 알아본 인증, 인가를 통해 가능하다.
인증, 인가를 구현하는 방법은 토큰
기반과 세션
기반 두 가지가 있다.
쿠키를 통한 인증 방식?
쿠키란 브라우저에 저장되는 작은 데이터 조각으로, ‘key-value’ 쌍으로 저장됨. 쿠키카 생성되어 있다면, 이를 삭제하거나 만료되지 않는 이상 서버와 통신할 경우 자동으로 주고 받는다. 이를 통해, 서버가 인증 상태를 기억하는 것처럼 만들 수 있다!
- 보통, 서버에서 클라이언트의 브라우저에 저장하도록 만든다. 서버에서 응답 헤더에
Set-Cookie
를 포함해 클라이언트의 브라우저에 쿠키를 저장하게 지시한다. - 클라이언트가 자바스크립트를 통해 쿠키를 다루는 방법도 있다!
세션을 통한 인증 방식
사용자와 서버 간의 연결이 활성화된 상태. 인증(Authentication)이 유지되고 있는 상태라고 해도 좋을듯.
간단한 설명을 하자면,
클라이언트가 로그인 한 경우, DB 에서 해당 계정과 비밀번호를 가진 유저 정보가 존재하는지 확인.
정보가 존재한다면, 이를 기반으로 유저정보를 가져와 Session Id 를 생성해 서버의 Session Storage 에 저장함.
그리고, 서버에 저장한 Session ID 를 브라우저 쿠키에 저장하기 위해 Set-Cookie 헤더를 담아 응답을 보낸다.
이 Session ID 가 존재한다면, 유저는 로그인 중인 상태이고 사라졌다면 로그아웃으로 판별한다.
세션 인증 이후 인가
클라이언트의 쿠키에 Session ID 를 가지고, 서버의 특정 리소스에 접근할 수 있는 권한이 있는지 없는지 확인하게 된다. 그러나, 이 방식은 한계가 존재한다고 한다.
- 확장성 문제: 세션 정보는 서버의 공간에 저장하고, 브라우저 쿠키는 접근할 수 있는 식별자만 가지고 있다. 예시로, 넷플릭스 같은 서비스는 회원 정보를 저장하는 서버와 미디어를 저장하는 서버는 분리되어 있을 것이다.
이때, 로그인 한 서버에서 넘겨준 session id 가 미디어 저장 서버에서도 유효하도록 연동해줘야한다. 종류가 다양해질 수록 이 과정은 복잡해진다.
메모리 사용량 증가: 서버가 다양한 유저들의 세션 정보까지 저장해야하기에 규모가 큰 경우 메모리 사용량이 급격히 증가한다.
상태 유지의 복잡성: http 는 무상태성(stateless) 인데, 세션을 이용하면 RESTful 원칙과 맞지 않게 된다.
보안 문제, session ID 만 탈취하면 타인이 세션을 가로채버릴 수 있다.
== 이것을 해결하기 위해 JWT(Json Web Token)을 사용한다.
토큰을 이용한 인증 방식
토큰을 통해 서버와 연결을 유지하지 않고도 인증이 가능하다. 토큰이란, 암호화 또는 인코딩한 인증 정보를 말한다.
JWT(Json Web Token)은 인코딩 방식을 이용한다. 암호화한 경우는 복호화 키가 필요하지만, JWT 는 필요 없다.
JWT란?
토큰 기반 인증 방식에서 사용하는 토큰으로, Header
, Payload
, Signature
3가지로 구성되어 있다.
헤더(Header): 어떤 종류의 토큰인지, 어떤 알고리즘으로 서명되었는지 알려줌.
본문(Payload): 실제로 중요한 데이터가 포함되어 있음. 사용자 ID, 토큰의 만료시간 등 정보.
서명(Signature): 클라이언트에서는 이를 다루지 않음. 서버에서, secret key 를 통해 토큰이 훼손되지 않았는지 확인하는 역할.
토큰 기반 인증 이후 인가
- 로그인 시 서버에 있는지 확인
- 유효하면, 유저 정보 데이터를 가져옴
- Secret key 기반으로 JWT 생성
- 응답으로 클라이언트에선 token 쿠키에 저장
- 클라이언트의 Web storage 에 토큰 저장함(사실 쿠키/로컬스토리지/세션스토리지 세 가지 공간 모두 가능)
세션과 토큰을 함께 사용하는 경우도 있지만, 현재 수준에서는 고려하지 않아도 될 것 같다.