[인증] 사용자 인증과 인가를 구현하는 방법과 문제점 알아보기
🤔 인증과 인가
인증 (Authorization) 이란 우리 서버에 접근하는 사용자의 신원을 확인하는 과정이다. 이를 위해서는 사용자마다 식별 가능한 정보가 필요하다.
인가 (Authentication) 이란 인증된 사용자가 접근할 수 있는 자원인지 확인하는 과정이다.
😛인증과 인가를 구현하는 방법
HTTP는 기본적으로 무상태성 (stateless)이기 때문에 인증 정보를 유지하기 위해서 사용자를 식별할 수 있는 인증 정보를 어디엔가 저장해야 한다. 이 정보를 저장하는 위치와 방법은 다양하다.
브라우저에 인증 정보를 저장하는 방법
세션 (session) 이란 사용자가 서버와 상호작용하기 위한 하나의 단위를 의미한다. 사용자가 서버에게 접근을 허가받았을 때 세션 아이디를 발급한다. 넓은 개념에서 하나의 연결이 유효한 상태인 기간을 의미할 수 있다.
세션 스토리지
브라우저 탭마다 고유한 세션 스토리지를 가지고 있다. 브라우저가 열려 있는 기간 단위를 세션이라고 표현한다. 탭이 닫히면 자동으로 세션이 종료되며 데이터도 삭제되는 특성이 있다.
쿠키와 다르게 서버와 통신하기 위한 용도가 아닌 클라이언트 측에서 접근하기 위한 공간이다.
로컬 스토리지
브라우저에 데이터를 영구적으로 저장한다. 브라우저가 닫혀도 데이터를 유지한다.
장기적인 데이터를 저장하는 데 용이하다.
쿠키
서버와의 통신 과정에서 사용된다. 영구 쿠키 (Persistent Cookie)의 경우 만료 시간이 지나면 브라우저에서 삭제된다. 세션 쿠키 (Session Cookie)의 경우 브라우저가 종료되면 자동으로 삭제된다.
자바 스크립트 코드로 쉽게 탈취될 수 있다. 따라서 HttpOnly 플래그를 설정하여 쿠키에 접근하지 못하도록 막을 수 있다.
Set-Cookie: username=Jaejun; Expires=Wed, 13 Oct 2024 07:28:00 GMT; Path=/; Secure; HttpOnly
서버에 인증 정보를 저장하는 방법
세션 (Session)
서버 측 세션은 브라우저의 세션 스토리지와 다른 개념이다.
사용자의 인증 요청을 기억하는 시간 단위를 세션으로 칭한다.
세션 정보를 저장하는 방식도 여러 가지이다.
서버의 메모리에 저장하는 방식
서버의 메모리에 세션 아이디와 사용자 정보를 매칭하여 저장한다.
세션 아이디를 만들어서 넘겨주고 브라우저에서는 세션 아이디를 저장한다. 세션이 탈취된 경우 서버에서 삭제하기만 하면 세션 정보를 이용할 수 없어서 안전하다. 메모리에 저장되기 때문에 읽고 쓰는 속도도 빠르다.
하지만 세션은 서버의 메모리에 저장하기 때문에 서버가 스케일 아웃 상태인 경우 이미 로그인한 사용자임에도 인증하지 못하는 상황이 생길 수 있다. 이를 해결하기 위해 Sticky Session (세션 복제) 등의 과정이 필요하다.
데이터베이스에 저장하는 방식
서버 간 데이터 공유가 쉬워지고 서버의 확장이나 재부팅 등에도 세션 데이터의 정보가 영속적으로 유지 가능하다.
하지만 읽기 및 쓰기 속도가 느리며 복잡하다는 단점이 있다. 추가적인 리소스가 필요하다.
요청과 응답에 인증 정보를 저장하는 방법
브라우저나 서버 혹은 데이터베이스에 저장하는 것이 아닌 HTTP 방식의 요청과 응답에 인증 정보를 저장할 수 있다. 토큰이라는 문자열에 사용자 인증 정보를 저장하고, 클라이언트가 서버에게 자원을 요청할 때 토큰을 헤더에 담아 보낸다.
토큰 (Token)
HTTP Set-Cookie 헤더에 토큰을 담아 보내면 브라우저 쿠키에서 토큰을 관리하는 방식이다.
대표적으로 JWT (Json Web Token)을 사용할 수 있다. 시크릿 키를 사용해 인코딩하며 토큰 내부에 중요한 정보를 담을 수 있다는 것이 장점이다. 세션 데이터베이스의 문제점이었던 확장성에도 용이하게 사용될 수 있다.
JWT (Json Web Token)
여러 가지 토큰을 사용한 인증 방식이 있지만 JWT 를 사용한 방식이 가장 대표적인 이유는 서버가 상태를 저장할 필요가 없으며 간단하고 문자열의 길이가 일정하기 때문이다.
Header와 Payload, Signature로 구분되며 Header와 Payload는 각각 Base64Url로 인코딩되었다. 시크릿키를 사용하여 디코딩할 수 있고 이는 Signature 란에서 서명되어 데이터의 무결성을 보장할 수 있다.
AccessToken과 Refresh Token
서버에 접근하기 위한 토큰을 Access Token이라고 한다. Access Token이 탈취당한 경우 사용자처럼 자원에 접근할 수 있다. 이를 해결하기 위해 만료 기간을 정한다. 만료 기간이 짧으면 사용자의 불편함이 생기기 때문에 Refresh Token이라는 개념을 사용한다. Refresh Token은 발급한 Access Token이 만료되었을 때 새로운 Access Token을 발급하기 위한 티켓 같은 것이다. 브라우저는 Refresh Token을 저장하고 만료되는 시점마다 이를 사용해 Access Token의 재발급 요청을 보낸다.