You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
회원 기능을 구현하기 위해 사용되는 대표적인 방식에는 Session 방식과 Token 방식이 있다.
Session
세션 기반 인증에서는 서버 측에서 클라이언트의 세션을 관리한다. 사용자가 로그인하면 서버는 세션 스토리지에 세션 정보를 저장하고, 클라이언트에게 세션 ID를 전송한다. 이후 클라이언트는 쿠키를 통해 세션 ID를 서버에 전송하여 인증을 수행한다. 세션 정보는 서버의 메모리나 데이터베이스에 저장된다.
Token
대표적인 토큰 방식인 JWT 방식은, 사용자가 로그인을 하면 서버에서 Access token 을 발급하며, 클라이언트는 이후 요청 시 Access Token 을 포함해 서버로 전송한다. 토큰은 서버가 아닌 클라이언트 측에서 저장되며, 서버는 이 토큰을 검증하기만 하면 된다.
Session VS Token
서버 부하: Session < Token
JWT Token 방식이 등장한 주요 이유중 하나는 세션 기반 인증 방식의 서버 부하를 줄이기 위함이다. 세션 방식은 사용자가 요청할 때마다 세션 스토리지에 접근해서 데이터를 확인하고, 그에 따라 사용자의 권한을 인가하는데, 인터넷이 보급되고 사용자 수가 많아지면서 세션 데이터를 조회하는 데 서버 비용과 부하가 커지기 시작했다.
JWT 같은 Token 방식을 사용하면, 사용자의 권한을 인가 할 때, 서버는 Access Token 의 유효성만 검증하면 되기 때문에 스토리지를 거칠 필요가 없다. Access Token 자체에 사용자의 권한 정보와 만료 기간이 포함되어 있기 떄문이다. 물론 Refresh Token 을 추가해서 구현한 경우, 그것으로 새로운 Access Token을 발급할 때는 서버에서 데이터베이스를 조회할 필요가 있지만, 이 방식으로 전체적인 데이터베이스 호출 빈도가 줄어들어 서버 부하를 크게 감소시킬 수 있다.
확장성, 상태 관리: Session < Token
Session 기반 인증은 서버 측에서 상태를 저장하기 때문에, 서버가 많은 세션 데이터를 처리해야 하는 상황에서 확장성이 떨어진다. 모든 요청이 세션 스토리지에 접근해야 하는데, 서버 아키텍쳐가 복잡해져도 세션 스토리지에 의존해야 한다.
하지만, Token 방식은 상태를 저장하지 않는 Stateless 방식이기 떄문에 서버는 JWT Secret 만 알고 있으면 클라이언트 검증이 가능하므로 서버 간 부하 분산이 용이해지고 동기화 문제가 줄어들어 서버 확장에 유리하다. 또한 HTTP 도 Stateless 이기 때문에 함께 사용하면 무상태성으로 서버를 구축할 수 있다.
보안: Session > Token
다만, Token 방식은 세션 방식에 비해 보안성이 다소 희생될 수 있다. Access Token 이 유효한 기간 동안에는 해당 토큰을 가지고 있는 사람이 누구든 인가가 가능하므로 토큰이 유출될 경우 유효 기간 내에 대처할 방법이 없기 때문에 악용될 위험이 있다.
반면, 세션 방식은 클라이언트에서 민감한 정보를 보관하지 않고, 세션을 서버에서 관리하기 때문에 서버에서 임의로 세션을 종료하거나 만료시킬 수 있다.
구현: Session > Token
세션 방식이 더 직관적이고 간단한 구조를 가지고 있다. 또한 프레임워크(Spring 등)에서 세션과 쿠키 관리를 지원한다.
토큰 방식은 개발자가 페이로드에 들어갈 정보등 토큰 방식의 이점을 살리기 위해서 여러가지 신경 써야할 점이 많다.
JWT 가 인기 많은 이유?
마이크로서비스 아키텍처에서는 서버 간 상태를 공유하는 것이 어려운 경우가 많다. 이럴 때는 서버가 상태를 저장할 필요가 없는 JWT 같은 방식이 유리하다.
OAuth 2.0과 같은 인증 표준에서 JWT를 사용하면서 그 인기가 증가했다. 많은 웹 애플리케이션과 API가 JWT를 사용하여 인증과 인가를 처리한다.
하지만, 인기가 많다는 것은 기술 선택의 이유가 되지 않는다. 합당한 이유를 찾고 프로젝트에 적용시키는게 좋다.
그래서 어떤 서비스를 만들떄 어떤 방식이 적합할지 정리해봤다.
그래서 뭐 쓰지
웹 서비스
규모가 너무 크거나 뛰어난 확장성이 요구되지 않는다면 (대부분의 서비스) Session 방식이 적절하다. Redis 인메모리 스토리지를 사용하면 성능과 확장성도 어느정도 커버 가능하다. 또한 구현도 어렵지 않다.
하지만 모바일 앱 서비스에서는 어떨까??
모바일 앱 서비스
세션 방식으로 구현하려면, 모바일 애플리케이션에는 쿠키가 기본적으로 사용되지 않으므로 앱 내에 저장해야 한다.
또한 세션 ID 전송과 수신을 직접 HTTP 요청에 포함시켜서 구현해야 한다.
그리고, 앱은 백그라운드나 포그라운드 상태로 자주 전환되므로, 세션 상태를 지속적으로 유지하기 어렵다. 앱이 백그라운드로 전환되거나 장시간 실행되지 않은 경우 세션이 만료될 수 있으며, 이를 처리하는 로직을 별도로 구현해야 한다. 자동 로그인과 함께 세션 종료 로직을 구현하기 복잡하다.
따라서 대부분의 모바일 앱 서비스에서는 세션 방식보다는 토큰 기반 인증 방식이 더 적절한 선택이다.
각 기술을 사용할 때 고려할 점
Session 구현 시 유의점
세션 유추 및 만료 설정
세션 ID가 유추 가능하면 안된다. 사용자가 로그인 성공 후 세션 아이디를 제공할 때, 예측 불가능한 값으로 제공해야 한다.
또한 불필요하게 세션을 길게 유지하지 않도록 해야 한다. 사용자가 일정 시간 활동이 없을 경우 세션이 종료되도록 구현하면 좋다.
세션 ID 탈취
세션 ID가 클라이언트에게 탈취되면 안되므로, HttpOnly 플래그를 쿠키에 설정하여 자바스크립트가 세션 ID에 접근할 수 없게 해야한다.
또한 Secure 플래그로 세션 ID가 HTTPS를 통해서만 전송되도록 해야한다.
Session 구현 시 사용할 기술 스택
데이터베이스
영구 저장을 제공하지만 인메모리 기반 스토리지보다는 느리다.
RDBMS (MySQL, PostGreSQL)
세션 저장에 적합하지는 않지만 소규모 프로젝트에서 기술 스택을 최소화 할꺼면 사용해도 그럭저럭 잘 돌아간다.
NoSQL (MongoDB)
NoSQL 기반 DB 스토리지이다. (인메모리 아님) 대규모 확장성이나 유연성이 요구될 경우 적합할 수 있다.
서버 부하가 걱정이 된다면, Session 정보를 저장할 때 데이터베이스 대신, 인메모리 스토리지 를 사용하면 세션 데이터를 메모리에 저장하여 빠르게 접근할 수 있다.
단, 서버 재시작 시 초기화되는 것을 고려해서 처리해야 한다.
인메모리
Redis 매우 빠른 인메모리 데이터 스토어로, 세션 관리를 위한 캐시로 널리 사용된다. 세션 데이터를 메모리에 저장하여 빠르게 접근할 수 있고, 클러스터링 및 복제를 지원해 확장성이 좋아 주로 분산 서버 환경에서 세션을 공유하기 위해 많이 사용된다.
AWS ElastiCache (Redis 기반)
Redis 기반 캐시 서비스로 클라우드 환경에서 관리가 용이하다. 운영 부담이 감소한다. 대신, 클라우드 비용이 발생할 수 있음을 생각해야 한다.
Token 구현 시 유의점
JWT 방식은 세션 방식에 비해 복잡하므로 특히 신경써서 구현해야 세션 방식 대비 이점을 챙길 수 있다.
스토리지 접근 매번 하면 안됨
Access Token 을 요청에 담아서 보낼 때 마다, 토큰의 정보를 활용해 스토리지에 매번 접근하는 로직을 작성하는 실수를 하곤 한다. 이렇게 구현할 경우 세션 방식에 비해 장점이 흐려진다. 확장성은 물론이고 성능도 이점을 챙기지 못해서 장점 없는 토큰 방식으로 구현하기 쉽다.
민감한 정보 담으면 안됨
JWT 토큰의 Payload (Claim) 에는 "식별에 필요한 최소한의 정보" 만 담아야 한다.
디코딩이 쉽기 때문에, 탈취 당할 경우 원본 데이터를 보기 매우 쉽다. 민감한 정보를 담으면 안된다. 누군가에게 탈취 당하더라도 큰 문제가 발생하지 않는 정보를 담아야 한다. (내부 값 암호화도 좋은 방법은 아니다. 매 요청마다 복호화가 한번 더 들어가기 때문에)
Secret Key 긴 무작위 값으로
Signature 의 secret 를 복잡한 무작위 값으로 해야한다. 이 값으로 토큰의 유효성을 검증하기 때문이다.
알고리즘
HS256은 써야한다.
토큰 탈취
토큰이 탈취될 경우 그것을 알고있어도 막을 수가 없기 때문에 보안을 강화해서 토큰 탈취 가능성을 낮춰야 한다.
그리고 Refresh Token 을 사용해서 Access Token 의 유효기간을 짧게 사용하자.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Session & Token
회원 기능을 구현하기 위해 사용되는 대표적인 방식에는 Session 방식과 Token 방식이 있다.
Session
세션 기반 인증에서는 서버 측에서 클라이언트의 세션을 관리한다. 사용자가 로그인하면 서버는 세션 스토리지에 세션 정보를 저장하고, 클라이언트에게 세션 ID를 전송한다. 이후 클라이언트는 쿠키를 통해 세션 ID를 서버에 전송하여 인증을 수행한다. 세션 정보는 서버의 메모리나 데이터베이스에 저장된다.
Token
대표적인 토큰 방식인 JWT 방식은, 사용자가 로그인을 하면 서버에서 Access token 을 발급하며, 클라이언트는 이후 요청 시 Access Token 을 포함해 서버로 전송한다. 토큰은 서버가 아닌 클라이언트 측에서 저장되며, 서버는 이 토큰을 검증하기만 하면 된다.
Session VS Token
서버 부하: Session < Token
JWT Token 방식이 등장한 주요 이유중 하나는 세션 기반 인증 방식의 서버 부하를 줄이기 위함이다. 세션 방식은 사용자가 요청할 때마다 세션 스토리지에 접근해서 데이터를 확인하고, 그에 따라 사용자의 권한을 인가하는데, 인터넷이 보급되고 사용자 수가 많아지면서 세션 데이터를 조회하는 데 서버 비용과 부하가 커지기 시작했다.
JWT 같은 Token 방식을 사용하면, 사용자의 권한을 인가 할 때, 서버는 Access Token 의 유효성만 검증하면 되기 때문에 스토리지를 거칠 필요가 없다. Access Token 자체에 사용자의 권한 정보와 만료 기간이 포함되어 있기 떄문이다. 물론 Refresh Token 을 추가해서 구현한 경우, 그것으로 새로운 Access Token을 발급할 때는 서버에서 데이터베이스를 조회할 필요가 있지만, 이 방식으로 전체적인 데이터베이스 호출 빈도가 줄어들어 서버 부하를 크게 감소시킬 수 있다.
확장성, 상태 관리: Session < Token
Session 기반 인증은 서버 측에서 상태를 저장하기 때문에, 서버가 많은 세션 데이터를 처리해야 하는 상황에서 확장성이 떨어진다. 모든 요청이 세션 스토리지에 접근해야 하는데, 서버 아키텍쳐가 복잡해져도 세션 스토리지에 의존해야 한다.
하지만, Token 방식은 상태를 저장하지 않는 Stateless 방식이기 떄문에 서버는 JWT Secret 만 알고 있으면 클라이언트 검증이 가능하므로 서버 간 부하 분산이 용이해지고 동기화 문제가 줄어들어 서버 확장에 유리하다. 또한 HTTP 도 Stateless 이기 때문에 함께 사용하면 무상태성으로 서버를 구축할 수 있다.
보안: Session > Token
다만, Token 방식은 세션 방식에 비해 보안성이 다소 희생될 수 있다. Access Token 이 유효한 기간 동안에는 해당 토큰을 가지고 있는 사람이 누구든 인가가 가능하므로 토큰이 유출될 경우 유효 기간 내에 대처할 방법이 없기 때문에 악용될 위험이 있다.
반면, 세션 방식은 클라이언트에서 민감한 정보를 보관하지 않고, 세션을 서버에서 관리하기 때문에 서버에서 임의로 세션을 종료하거나 만료시킬 수 있다.
구현: Session > Token
세션 방식이 더 직관적이고 간단한 구조를 가지고 있다. 또한 프레임워크(Spring 등)에서 세션과 쿠키 관리를 지원한다.
토큰 방식은 개발자가 페이로드에 들어갈 정보등 토큰 방식의 이점을 살리기 위해서 여러가지 신경 써야할 점이 많다.
JWT 가 인기 많은 이유?
마이크로서비스 아키텍처에서는 서버 간 상태를 공유하는 것이 어려운 경우가 많다. 이럴 때는 서버가 상태를 저장할 필요가 없는 JWT 같은 방식이 유리하다.
OAuth 2.0과 같은 인증 표준에서 JWT를 사용하면서 그 인기가 증가했다. 많은 웹 애플리케이션과 API가 JWT를 사용하여 인증과 인가를 처리한다.
하지만, 인기가 많다는 것은 기술 선택의 이유가 되지 않는다. 합당한 이유를 찾고 프로젝트에 적용시키는게 좋다.
그래서 어떤 서비스를 만들떄 어떤 방식이 적합할지 정리해봤다.
그래서 뭐 쓰지
웹 서비스
규모가 너무 크거나 뛰어난 확장성이 요구되지 않는다면 (대부분의 서비스) Session 방식이 적절하다.
Redis 인메모리 스토리지를 사용하면 성능과 확장성도 어느정도 커버 가능하다. 또한 구현도 어렵지 않다.
하지만 모바일 앱 서비스에서는 어떨까??
모바일 앱 서비스
세션 방식으로 구현하려면, 모바일 애플리케이션에는 쿠키가 기본적으로 사용되지 않으므로 앱 내에 저장해야 한다.
또한 세션 ID 전송과 수신을 직접 HTTP 요청에 포함시켜서 구현해야 한다.
그리고, 앱은 백그라운드나 포그라운드 상태로 자주 전환되므로, 세션 상태를 지속적으로 유지하기 어렵다. 앱이 백그라운드로 전환되거나 장시간 실행되지 않은 경우 세션이 만료될 수 있으며, 이를 처리하는 로직을 별도로 구현해야 한다. 자동 로그인과 함께 세션 종료 로직을 구현하기 복잡하다.
각 기술을 사용할 때 고려할 점
Session 구현 시 유의점
세션 ID가 유추 가능하면 안된다. 사용자가 로그인 성공 후 세션 아이디를 제공할 때, 예측 불가능한 값으로 제공해야 한다.
또한 불필요하게 세션을 길게 유지하지 않도록 해야 한다. 사용자가 일정 시간 활동이 없을 경우 세션이 종료되도록 구현하면 좋다.
세션 ID가 클라이언트에게 탈취되면 안되므로, HttpOnly 플래그를 쿠키에 설정하여 자바스크립트가 세션 ID에 접근할 수 없게 해야한다.
또한 Secure 플래그로 세션 ID가 HTTPS를 통해서만 전송되도록 해야한다.
Session 구현 시 사용할 기술 스택
데이터베이스
영구 저장을 제공하지만 인메모리 기반 스토리지보다는 느리다.
RDBMS (MySQL, PostGreSQL)
세션 저장에 적합하지는 않지만 소규모 프로젝트에서 기술 스택을 최소화 할꺼면 사용해도 그럭저럭 잘 돌아간다.
NoSQL (MongoDB)
NoSQL 기반 DB 스토리지이다. (인메모리 아님) 대규모 확장성이나 유연성이 요구될 경우 적합할 수 있다.
서버 부하가 걱정이 된다면, Session 정보를 저장할 때 데이터베이스 대신, 인메모리 스토리지 를 사용하면 세션 데이터를 메모리에 저장하여 빠르게 접근할 수 있다.
단, 서버 재시작 시 초기화되는 것을 고려해서 처리해야 한다.
인메모리
Redis
매우 빠른 인메모리 데이터 스토어로, 세션 관리를 위한 캐시로 널리 사용된다. 세션 데이터를 메모리에 저장하여 빠르게 접근할 수 있고, 클러스터링 및 복제를 지원해 확장성이 좋아 주로 분산 서버 환경에서 세션을 공유하기 위해 많이 사용된다.
AWS ElastiCache (Redis 기반)
Redis 기반 캐시 서비스로 클라우드 환경에서 관리가 용이하다. 운영 부담이 감소한다. 대신, 클라우드 비용이 발생할 수 있음을 생각해야 한다.
Token 구현 시 유의점
JWT 방식은 세션 방식에 비해 복잡하므로 특히 신경써서 구현해야 세션 방식 대비 이점을 챙길 수 있다.
스토리지 접근 매번 하면 안됨
Access Token 을 요청에 담아서 보낼 때 마다, 토큰의 정보를 활용해 스토리지에 매번 접근하는 로직을 작성하는 실수를 하곤 한다. 이렇게 구현할 경우 세션 방식에 비해 장점이 흐려진다. 확장성은 물론이고 성능도 이점을 챙기지 못해서 장점 없는 토큰 방식으로 구현하기 쉽다.
민감한 정보 담으면 안됨
JWT 토큰의 Payload (Claim) 에는 "식별에 필요한 최소한의 정보" 만 담아야 한다.
디코딩이 쉽기 때문에, 탈취 당할 경우 원본 데이터를 보기 매우 쉽다. 민감한 정보를 담으면 안된다. 누군가에게 탈취 당하더라도 큰 문제가 발생하지 않는 정보를 담아야 한다. (내부 값 암호화도 좋은 방법은 아니다. 매 요청마다 복호화가 한번 더 들어가기 때문에)
Secret Key 긴 무작위 값으로
Signature 의 secret 를 복잡한 무작위 값으로 해야한다. 이 값으로 토큰의 유효성을 검증하기 때문이다.
알고리즘
HS256은 써야한다.
토큰 탈취
토큰이 탈취될 경우 그것을 알고있어도 막을 수가 없기 때문에 보안을 강화해서 토큰 탈취 가능성을 낮춰야 한다.
그리고 Refresh Token 을 사용해서 Access Token 의 유효기간을 짧게 사용하자.
Beta Was this translation helpful? Give feedback.
All reactions