누군가 갑자기 session과 토큰이 어떻게 다른지 물어보았습니다.
실제로 구현도 해봤고 아는 내용이라고 생각했지만 상대방이 이해할 수 있게 설명하는 것은 다르다는 것을 느꼈습니다.
세션 기반 인증
장점:
- 즉각적인 무효화 가능: 서버에서 세션을 관리하기 때문에 특정 세션을 즉시 만료시키거나 무효화할 수 있어, 로그아웃 처리나 보안 사고 발생 시 대응이 용이합니다.
- 보안: 세션 ID만 클라이언트에 저장되고 실제 사용자 정보는 서버에 보관되므로, 클라이언트 측에서 민감한 정보가 노출될 위험이 적습니다.
단점:
- 서버 자원 소모: 사용자 인증 정보(세션 데이터)를 서버에 저장해야 하므로, 사용자 수가 많아지면 서버의 저장 공간 및 메모리 자원을 많이 소모하게 됩니다.
- 확장성 문제: 여러 대의 서버를 사용할 경우, 사용자가 다른 서버로 요청을 보낼 때마다 세션 정보를 공유해야 하는 문제가 발생하며, 이는 로드 밸런싱 환경에서 복잡성을 증가시킵니다.
- CORS(Cross-Origin Resource Sharing) 제약: 도메인이 다른 환경에서 쿠키를 주고받는 데 제약이 있어, MSA(마이크로서비스 아키텍처)나 모바일 환경에서는 구현이 복잡해질 수 있습니다.
세션 기반 인증의 단점 극복 방안
세션 기반 인증의 주요 단점은 확장성 부족과 서버 자원 소모였습니다. 이를 극복하기 위한 방법은 다음과 같습니다.
- 분산 세션 관리 시스템 도입 (Redis, Memcached 등)
- 문제점: 여러 대의 서버를 운영할 때, 각 서버가 자신의 로컬 메모리에 세션 정보를 저장하면, 사용자의 요청이 다른 서버로 라우팅될 경우 기존 세션을 찾을 수 없어 재로그인을 해야 하는 문제가 발생합니다.
- 해결책: 세션 정보를 모든 서버가 공유하는 별도의 저장소(예: Redis, Memcached, 데이터베이스)에 저장합니다. 이렇게 하면 어떤 서버로 요청이 오든 동일한 세션 정보에 접근할 수 있어, 서버 확장에 용이해집니다.
- Sticky Session (세션 고정)
- 문제점: 위와 동일하게 여러 서버 환경에서 세션 일관성 문제가 발생합니다.
- 해결책: 로드 밸런서가 특정 사용자의 요청을 항상 동일한 서버로 보내도록 설정합니다. 이는 비교적 간단하게 세션 문제를 해결할 수 있지만, 특정 서버에 부하가 집중되거나 서버가 다운될 경우 다른 서버로 failover가 원활하지 않을 수 있어 완전한 해결책은 아닙니다.
- 세션 타임아웃 및 주기적인 세션 삭제
- 문제점: 사용하지 않는 세션이 서버 메모리에 계속 남아있으면 자원 소모가 심해집니다.
- 해결책: 일정 시간 이상 활동이 없는 세션은 자동으로 만료시키거나, 주기적으로 만료된 세션을 정리하여 서버 자원을 효율적으로 관리합니다.
토큰 기반 인증
장점:
- Stateless(무상태성): 서버가 클라이언트의 상태를 저장하지 않습니다. 토큰 자체가 사용자의 인증 정보를 포함하고 있어 서버의 부담을 줄이고 확장성을 향상시킵니다.
- 확장성: 서버의 상태를 유지할 필요가 없어 여러 대의 서버에 쉽게 분산할 수 있고, 로드 밸런싱에 유리합니다. 또한, 여러 서비스 간에 토큰을 공유하여 사용할 수 있어 마이크로서비스 환경에 적합합니다.
- CORS에 유리: 토큰은 HTTP 헤더를 통해 전달되므로 도메인 제약 없이 요청을 보낼 수 있어, 다양한 클라이언트(웹, 모바일 앱)에서 유연하게 사용할 수 있습니다.
- 성능 향상: 사용자가 자격 증명을 보내는 횟수를 줄일 수 있습니다.
단점:
- 즉각적인 무효화 어려움: 토큰은 한 번 발급되면 유효기간이 만료될 때까지 유효합니다. 따라서 강제 로그아웃이나 토큰 탈취 시 즉각적으로 토큰을 무효화하기 어렵습니다. (Redis 등을 활용한 블랙리스트 구현으로 해결 가능)
- 토큰 탈취 시 위험: 클라이언트 측에 토큰이 저장되므로, XSS(Cross-Site Scripting) 공격 등으로 토큰이 탈취될 경우 보안에 취약해질 수 있습니다.
- 토큰 크기: 토큰에 많은 정보를 담을수록 토큰의 크기가 커져 네트워크 부하를 증가시킬 수 있습니다.
토큰 기반 인증의 단점 극복 방안
토큰 기반 인증의 주요 단점은 즉각적인 무효화 어려움과 토큰 탈취 시 보안 취약성이었습니다. 이를 극복하기 위한 방법은 다음과 같습니다.
- 리프레시 토큰(Refresh Token) 도입
- 문제점: 액세스 토큰은 무상태성 때문에 한번 발급되면 만료되기 전까지 강제로 무효화하기 어렵습니다. 만약 유효기간이 긴 액세스 토큰이 탈취되면 큰 보안 위협이 됩니다.
- 해결책: 유효기간이 짧은 액세스 토큰(Access Token)과 유효기간이 긴 리프레시 토큰(Refresh Token)을 함께 사용합니다.
액세스 토큰은 실제 리소스 접근에 사용되며, 탈취되어도 유효기간이 짧아 피해를 최소화합니다.
리프레시 토큰은 서버에 안전하게 저장(예: HTTP-only 쿠키)하고, 액세스 토큰이 만료되면 이를 사용하여 새로운 액세스 토큰을 발급받습니다.
서버에서는 리프레시 토큰을 관리하여 필요시 개별 리프레시 토큰을 즉시 만료시킬 수 있어, 토큰 강제 만료 및 로그아웃 기능을 구현할 수 있습니다.
- 블랙리스트(Blacklist) 또는 화이트리스트(Whitelist) 관리
- 문제점: 리프레시 토큰을 사용하더라도, 이미 발급된 액세스 토큰은 만료 시간까지 유효합니다.
- 해결책: 사용자가 로그아웃하거나 보안상의 이유로 토큰을 즉시 무효화해야 할 경우, 해당 토큰(혹은 토큰의 고유 ID)을 블랙리스트에 추가하여 서버에서 유효하지 않은 토큰으로 처리합니다. Redis와 같은 빠른 NoSQL 데이터베이스에 저장하여 검증하는 방식으로 구현할 수 있습니다.
- 토큰 저장 위치와 전송 보안 강화
- 문제점: 클라이언트 측에 저장되는 토큰(특히 액세스 토큰)은 XSS 공격 등으로 탈취될 위험이 있습니다.
- 해결책:
- HTTP-only 쿠키 사용: JavaScript로 쿠키에 접근하는 것을 막아 XSS 공격으로부터 토큰을 보호할 수 있습니다.
- HTTPS 프로토콜 사용: 모든 통신을 암호화하여 중간자 공격(Man-in-the-Middle Attack)으로부터 토큰이 탈취되는 것을 방지합니다.
- 로컬 스토리지 대신 세션 스토리지 사용: 브라우저 종료 시 토큰이 자동으로 삭제되도록 하여 지속적인 위협 노출 시간을 줄일 수 있습니다.
- 토큰 페이로드 최소화
- 문제점: 토큰에 많은 정보를 담으면 크기가 커져 네트워크 부하를 증가시킬 수 있습니다.
- 해결책: JWT 페이로드에는 필수적인 정보(예: 사용자 ID, 권한)만 담고, 추가적인 사용자 정보는 서버에서 데이터베이스 조회를 통해 가져오도록 합니다.
어떤 프로젝트에 어떤 인증이 더 적합한가요?
세션 기반 인증:
- 상태 유지가 중요한 경우: 전통적인 웹 애플리케이션처럼 서버에서 사용자 상태(예: 장바구니 정보, 로그인 상태)를 적극적으로 관리해야 하는 경우에 적합합니다.
- 소규모 서비스 또는 단일 서버 환경: 서버 확장 및 분산 환경의 복잡성을 크게 고려하지 않아도 되는 경우에 더 간단하게 구현할 수 있습니다.
토큰 기반 인증:
- SPA 및 모바일 애플리케이션: 백엔드 API와 프론트엔드가 분리된 SPA나 모바일 앱 환경에서 클라이언트가 서버에 구애받지 않고 유연하게 인증을 처리할 수 있습니다.
- 마이크로서비스 아키텍처: 여러 개의 독립적인 서비스들이 서로 통신해야 하는 복잡한 분산 시스템 환경에서 서비스 간의 인증을 효율적으로 처리할 수 있습니다.
- 확장성이 중요한 대규모 서비스: 사용자가 급증하거나 트래픽이 많아 서버 확장이 자주 필요한 서비스에 적합합니다.
어떤 방식을 더 많이 사용하고, 그 이유는 무엇인가요?
최근에는 토큰 기반 인증(특히 JWT) 방식이 더 많이 사용되는 추세입니다.
그 이유는 웹 서비스의 발전과 밀접하게 관련이 있습니다. 현대의 웹 애플리케이션은 SPA(Single Page Application), 모바일 앱, 그리고 다양한 마이크로서비스가 연동되는 복잡한 아키텍처를 가집니다. 이러한 환경에서 토큰 기반 인증은 다음과 같은 장점 때문에 선호됩니다.
- 확장성: 서버의 상태를 저장할 필요가 없어 서버 확장이 용이하고, 여러 서버 간의 세션 동기화 문제를 해결할 수 있습니다.
- 유연성: 특정 도메인에 종속되지 않고, 모바일 앱이나 다른 서비스와의 연동에도 유연하게 대처할 수 있습니다.
- 분산 환경에 적합: 마이크로서비스 아키텍처에서 각 서비스가 독립적으로 인증을 처리하거나 토큰을 공유할 수 있어 효율적입니다.
면접 인터뷰 예상 질문
- 세션 기반 인증과 토큰 기반 인증(JWT)의 차이점을 설명해 주세요.
- 각각의 장단점은 무엇이며, 어떤 상황에서 더 적합하다고 생각하나요?
- JWT(JSON Web Token)는 무엇이며, 어떻게 동작하는지 설명해 주세요.
- JWT의 구조(헤더, 페이로드, 서명)에 대해 아는 대로 설명해 주세요.
- 토큰 기반 인증에서 로그아웃은 어떻게 구현해야 할까요?
- 토큰이 탈취되었을 때 발생할 수 있는 문제점과 해결 방안은 무엇이 있을까요?
- 액세스 토큰(Access Token)과 리프레시 토큰(Refresh Token)은 무엇이며, 왜 두 가지 토큰을 함께 사용하는 것이 좋은가요?
- 세션 하이재킹(Session Hijacking)과 같은 공격에 대해 설명하고, 세션 기반 인증에서는 어떻게 방어할 수 있을까요?
- 토큰 기반 인증 시 발생할 수 있는 보안 취약점(예: XSS)은 무엇이며, 이를 어떻게 방지할 수 있을까요?
- 본인이 개발한 프로젝트에서는 어떤 인증 방식을 사용했고, 그 방식을 선택한 이유는 무엇인가요?
면접 인터뷰 답변
- 세션 기반 인증과 토큰 기반 인증(JWT)의 차이점을 설명해 주세요.
- 가장 큰 차이점은 유저의 상태를 서버가 직접 관리하느냐 아니냐의 차이라고 생각합니다. 토큰은 주로 JWT를 사용합니다. Header, Payload, Signature를 기반으로 하여 직렬화를 해주고 서버에 이 로그인 데이터를 저장하지 않습니다. 외부에서 이 토큰을 저장하고 있기 때문에 MSA같은 여러 서버를 사용할 때 혹은 Single Page Application할 때 유리합니다. 다만 외부에 이 토큰을 관리하고 토큰을 임의로 삭제가 불가능하기 때문에 토큰 탈취를 조심해야합니다.
그리고 session은 서버가 직접 로그인 데이터를 들고 있습니다.
그렇기 때문에 세션 만료나 로그아웃 기능을 만들 때 유리한 측면이 있습니다.
다만 서버가 직접 이 데이터를 가지고 있기 때문에 확장성면에서 떨어지는 문제가 있습니다.
- 각각의 장단점은 무엇이며, 어떤 상황에서 더 적합하다고 생각하나요?
- session 기반은 프론트 혹은 클라이언트 측에 세션 아이디만 주기 때문에 안정성 올라갑니다. 그리고 서버가 로그인 데이터를 직접 들고 있기 때문에 로그아웃 혹은 만료 기능을 넣기 쉽습니다.
하지만 서버가 직접 들고 있기 때문에 서버가 늘어났을 때 복잡해질 수 있어서 확장성이 떨어집니다.
토큰은 탈취 문제를 고려해야합니다.
서버 안이 아닌 외부에 이 토큰을 가지고 있기 때문에 이 토큰을 가지고 있다면 어디서든 쓸 수 있기 때문입니다.
하지만 확장성 높고 JWT같이 직렬화 역직렬화의 대한 최적화가 높기 때문에 성능상 유리할 수 있습니다.
- JWT(JSON Web Token)는 무엇이며, 어떻게 동작하는지 설명해 주세요.
- JWT는 Header, Payload, Signature를 종합하여 직렬화한 키라고 볼 수 있습니다.
- JWT의 구조(헤더, 페이로드, 서명)에 대해 아는 대로 설명해 주세요.
- Header에서 알고리즘을 고르고, payload에 유저를 식별할 수 있는 데이터를 집어넣고, Signature에 이 jwt의 비밀번호를 집어넣는 형식입니다.
- 토큰 기반 인증에서 로그아웃은 어떻게 구현해야 할까요?
- 토큰의 경우에는 유효기간을 정해야하는데 이 기간이 지나기 전까지는 삭제되지 않습니다.
그렇기 때문에 저는 redis를 사용하여 블랙리스트를 만들었습니다.
서버 측에서 만약 이 블랙리스트에 해당된다면 더 이상 이 토큰으로 로그인 상태를 유지할 수 없게 만들었습니다.
- 토큰이 탈취되었을 때 발생할 수 있는 문제점과 해결 방안은 무엇이 있을까요?
- 토큰이 탈취될 경우 어디서든 누구나 그 토큰을 사용하여 로그인할 수 있습니다.
이 문제를 해결하기 위해 토큰의 유효기간을 짧게 만듭니다.
토큰이 만료된다면 또 다시 로그인해야하는 번거로운 문제가 있기 때문에 accessToken과 refreshToken을 만들어 이 문제를 해결할 수 있습니다.
- 세션 하이재킹(Session Hijacking)과 같은 공격에 대해 설명하고, 세션 기반 인증에서는 어떻게 방어할 수 있을까요?
- 세션 하이재킹(Session Hijacking)은 공격자가 합법적인 사용자의 세션을 가로채서 해당 사용자인 것처럼 웹 애플리케이션에 접근하는 공격 기법입니다.
방어 방법은 여러가지 있습니다.
https를 사용하여 네트워크상에 sessionID 노출을 차단합니다.
secure과 httpOnly 쿠키 설정을 하여 https에서만 쿠키를 사용할 수 있게 합니다.
세션에 유효기간을 만들어 탈취된 세션의 대한 사용시간이 제한할 수 있습니다.
(추가로 SameSite 쿠키 속성 사용: SameSite=Strict 또는 Lax 설정을 통해 크로스 사이트 요청에서 쿠키가 전송되지 않도록 제한합니다.)
-
토큰 기반 인증 시 발생할 수 있는 보안 취약점은 무엇이며, 이를 어떻게 방지할 수 있을까요?
취약점으로는 XSS와 CSRF 방법으로 토큰이 탈취될 위험이 있습니다.
XSS의 문제를 해결하기 위해 HttpOnly 플래그가 설정된 쿠키를 사용하여 JavaScript에서 토큰에 접근할 수 없도록 해야합니다.
만약 로컬이나 세션 스토리지에 저장한다면 이런 취약점에 대응하기 어렵기 때문에 쿠키에 저장하고 설정을 잘 해줘야합니다.
-
본인이 개발한 프로젝트에서는 어떤 인증 방식을 사용했고, 그 방식을 선택한 이유는 무엇인가요?
저는 주로 토큰 기반 방식을 선호하여 사용했습니다.
프로젝트를 하다보면 최소한으로 만들었지만 점점 거대해지는 경향이 있습니다.
MSA까지는 아니더라도 서버가 여러 개가 되는 상황이 많이 발생하면서 프로젝트 때마다 처음부터 확장성에 대한 고려를 하게 되었습니다.
그래서 토큰 방식이 익숙해졌습니다.