서비스 환경에서 개인정보와 중요한 데이터를 보호하는 일은 무엇보다 중요하며, 사용자 경험`UX`을 저해하지 않는 효율적인 인증 체계가 필수적입니다.
이번 포스팅에서는 인증과 인가를 다루는 세션`Session`과 토큰`Token` 두 가지 방식의 개념과 차이점, 그리고 각 방식의 장단점에 대해 알아보도록 하겠습니다.
세션과 토큰에 대해 알아보기 전 인증`Authentication`과 인가`Authorization`, 그리고 HTTP의 비상태성`Stateless`에 대해 간단히 알아보도록 하겠습니다.
인증 (Authentication)
인증 (Authentication)은 사용자의 신원을 확인하는 과정으로 즉, 누구인지 확인하는 절차입니다.
쉽게말해 저희가 알고있는 `로그인`에 해당됩니다. 인증은 일반적으로 사용자에게 적절한 접근 권한을 부여하기 위한 첫 번째 단계로, 안전한 서비스 이용을 위한 기초를 마련합니다.
인가 (Authorization)
인가 (Authorization)는 `인증`된 사용자가 자원에 접근할 수 있는지를 결정하는 과정입니다.
주요 기능으로는 사용자가 어떤 행동을 할 수 있는지에 대한 권한 부여 및 제한이 있습니다.
즉, 사용자가 로그인 후 특정 페이지에 접근할 수 있는 권한이 있는지를 판단하는 과정입니다.
예를들어 일반 사용자에게 `작성, 조회, 수정, 삭제`의 일반적인 작업에 대한 권한이 부여되어 있을 경우, `USER1`이 작성한 게시글에 대해 `USER2`는 `USER1의 리소스에 대해 인가되어있지 않기 때문`에 수정 및 삭제가 불가능합니다.
같은 이유로 일반 사용자는 관리자 페이지에 대해 인가되어있지 않기때문에 관리자 페이지의 경우 일반 사용자는 접근이 불가능합니다.
HTTP의 비상태성 (Stateless)
HTTP의 비상태성 (Stateless)은 웹에서 클라이언트와 서버 간의 통신 방식 중 하나로, 서버가 클라이언트의 상태를 기억하지 않는 특성을 말합니다. 즉, 각 요청은 독립적이며 `이전 요청`의 정보나 상태를 저장하지 않습니다.
이런 특성 때문에 인증 정보를 저장하고 관리하기 위해 세션 또는 토큰 방식의 인증을 사용합니다.
특징
- 독립적인 요청
- 클라이언트가 서버에 요청할 때마다, 서버는 해당 요청을 독립적으로 처리합니다.
- 이전 요청에 대한 정보는 서버에 저장되지 않기 때문에, 클라이언트는 매 요청마다 필요한 모든 정보를 포함해야 합니다.
- 상태 정보 저장 없음
- 서버는 클라이언트의 상태를 유지하기 위해 추가적인 메모리를 사용하지 않아 자원의 효율적인 사용이 가능합니다.
- 즉, 서버가 클라이언트의 상태를 기억하지 않기 때문에, 로그인 세션이나 사용자 인증 상태를 관리하기 위해 추가적인 방법이 필요합니다. 이를 위해 주로 `세션(Session)` 또는 `토큰(Token)` 방식이 사용됩니다.
- 예측 가능성
- 클라이언트와 서버 간의 통신이 비상태성이기 때문에 각 요청은 예측 가능하고 처리하기가 간단합니다.
- 클라이언트가 보낸 요청만을 바탕으로 응답이 결정되어 요청의 처리 방식이 일관되게 유지됩니다.
세션(Session) 기반 인증
세션(Session)은 클라이언트와 서버 간의 상태를 유지하기 위한 방법으로, 사용자가 로그인하여 인증된 후 해당 사용자의 정보를 일정 기간 동안 서버가 기억할 수 있도록 합니다.
세션의 작동 방식
- `로그인 요청` : 사용자가 ID, Password를 입력하여 서버에 로그인 요청을 합니다.
- `사용자 유효성 검증` : 서버는 데이터베이스에 저장된 정보를 통해 사용자의 입력에 대해 유효성을 검증합니다.
- `세션 데이터 저장` : 유효성 검증이 완료된 후 서버는 해당 사용자에 대한 세션데이터를 서버메모리에 저장하고, 이를 식별 할 수 있는 세션 ID를 생성합니다.
- `세션 ID 전송` : 서버는 생성된 세션 ID를 클라이언트에게 쿠키 형태로 전송합니다.
- `세션 ID 저장` : 클라이언트는 서버로부터 전달받은 세션 ID를 쿠키에 저장합니다.
- `리소스 요청` : 이후 클라이언트는 서버에 요청할 때마다 쿠키에 포함된 세션 ID를 함께 전송합니다.
- `세션 유효성 검증` : 서버는 클라이언트로부터 받은 세션 ID를 사용하여 해당 세션 데이터를 조회하고, 유효한 세션인지 검증합니다.
- `응답 전송` : 세션이 유효할 경우, 서버는 요청에 대한 응답을 클라이언트에게 전송합니다.
세션의 장단점
장점
- 상태 유지
- 서버가 사용자 상태를 직접 관리하여 세션 정보를 통해 사용자 인증 상태를 쉽게 유지할 수 있습니다.
- 사용자는 로그인 후 여러 페이지를 탐색하면서 인증 정보를 반복적으로 입력할 필요가 없습니다.
- 보안성
- 세션 정보가 서버에 저장되어 클라이언트 측에 민감한 정보를 저장하지 않아 데이터 유출 위험이 줄어듭니다. 또한 서버에서 세션 정보를 쉽게 검증할 수 있습니다.
- 서버 제어
- 세션 정보가 서버에 저장되어 관리자가 세션을 즉각적으로 쉽게 제어할 수 있습니다.
- ex) 관리자가 특정 사용자`(비정상적인 사용자)`의 세션을 강제로 종료시키면 해당 사용자는 로그아웃되어 추가적인 접근이 차단됩니다.
- 사용자 경험 개선
- 사용자는 로그인 후 계속 인증된 상태로 서비스를 이용할 수 있어 편리합니다.
- 로그인 후 여러작업을 수행하는 것이 원활해집니다.
- 로깅 및 분석
- 서버는 세션 정보를 통해 사용자 행동을 추적하고 분석할 수 있어 사용자 맞춤형 서비스를 제공하는데 유리합니다.
단점
- 서버 자원 소모
- 모든 세션 정보를 서버 메모리에 저장하여 많은 사용자가 동시에 접속할 경우 서버의 메모리 사용량이 급증하여 서버에 부하가 발생할 수 있습니다.
- 스케일링의 어려움
- 세션 정보가 서버에 저장되기 때문에, 여러 서버 간의 세션 공유가 필요할 경우 복잡성이 증가합니다.
- ex) 여러 서버에서 로드 밸런싱을 사용하는 경우, 사용자의 세션이 특정 서버에만 존재하면 다른 서버에서 세션 정보를 확인할 수 없게 됩니다.
- 세션 하이재킹 위험
- 공격자가 세션 ID를 탈취하여 사용자의 세션을 가로채 공격자가 인증된 사용자로 가장할 수 있는 위험이 있습니다.
- ex) 사용자가 공용 Wi-Fi를 통해 서비스에 접속할 때 세션 ID가 노출되면, 공격자가 이를 이용해 사용자의 계정을 탈취할 수 있습니다.
- 장시간 비활성 상태에서의 불편함
- 사용자가 오랜 시간 동안 활동하지 않으면 세션이 만료될 수 있습니다. 이 경우 사용자는 다시 로그인을 해야 하므로 불편함이 발생할 수 있습니다.
- ex) 사용자가 몇 시간 동안 애플리케이션을 열어두고 아무 작업도 하지 않으면, 세션이 만료되어 다시 인증해야하며 이 과정에서 데이터 손실이 발생할 수 있습니다.
- 브라우저 종속성
- 세션 ID는 클라이언트의 쿠키에 저장되어 사용자가 다른 브라우저나 기기로 이동할 경우 인증상태가 유지되지 않습니다.
- ex) 사용자가 데스크탑에서 로그인 후 모바일 기기로 이동할 경우, 다시 로그인을 해야 하므로 사용자 경험이 저하됩니다.
세션 정리
`세션(Session) 기반 인증`은 클라이언트가 로그인 시 서버에 세션을 생성하고, 이를 통해 사용자의 인증 상태를 유지하는 방식입니다.
서버는 유효성 검증을 통해 세션 데이터를 메모리에 저장하고, 클라이언트에게 고유한 세션 ID를 쿠키로 전송합니다. 이후 클라이언트는 요청 시마다 세션 ID를 함께 전송하여 인증된 상태를 유지합니다.
세션 기반 인증은 직관적이고, 보안성과 사용자 경험을 개선하는데 유리하지만 서버 확장과 보안 관리에 추가적인 노력이 필요합니다.
JWT - 토큰(Token) 기반 인증
토큰(Token) 기반 인증은 사용자가 로그인하면 서버가 인증을 확인한 후 클라이언트에게 암호화된 토큰을 발급하여, 이후 요청에 토큰을 포함시켜 인증 상태를 유지하는 방식입니다.
이 방식은 특히 RESTful API와 같이 `무상태(Stateless)`로 동작하는 시스템에서 많이 사용됩니다.
토큰의 구조
JWT(Json Web Token)는 `Header`, `Payload`, `Signature` 3부분으로 이루어지며, Json 형태인 각 부분은 Base64로 인코딩 되어 표현됩니다.
Base64는 암호화된 문자열이 아닌, 같은 문자열에 대해 항상 같은 인코딩 문자열을 반환합니다.
헤더 (Header)
토큰의 헤더는 typ와 alg 두 가지 정보로 구성됩니다.
{
"alg": "HS256", // 알고리즘 방식을 지정, 서명(Signature) 및 토큰 검증에 사용
"typ": "JWT" // 토큰의 타입을 지정
}
페이로드 (Payload)
토큰의 페이로드에는 토큰에서 사용할 정보의 조각들인 클레임(Claim)이 포함됩니다.
클레임은 3가지로 분류되며, Json`Key-Value` 형태로 다수의 정보를 담을 수 있습니다.
등록된 클레임 (Registered Claim)
등록된 클레임은 토큰 정보를 표현하기 위해 이미 정해진 종류의 데이터로, 모두 선택적으로 작성이 가능합니다.
{
"iss": "https://tao-tech.tistory.com", // 토큰 발급자(Issuer): 이 토큰을 발급한 주체의 URL
"sub": "tao123456", // 사용자 ID(Subject): 사용자에 대한 고유 식별자 (보통 email 또는 ID에 해당)
"aud": "https://tao-tech.tistory.com", // 대상(Audience): 이 토큰이 사용될 대상의 URL
"exp": 1730807795, // 토큰 만료 시간(Expiration Time): (2024년 11월 5일)
"nbf": 1730634995, // 토큰 유효 시작 시간(Not Before): (2024년 11월 3일)
"iat": 1730721395, // 토큰 발급 시간(Issued At): (2024년 11월 4일)
"jti": "unique-token-id-abcdef123456" // 토큰의 고유 ID(JWT ID): 이 토큰을 고유하게 식별하기 위한 ID
}
공개 클레임 (Public Claim)
공개 클레임은 사용자 정의 클레임으로, 공개용 정보를 위해 사용되며, 충돌 방지를 위해 URI 포맷을 사용합니다.
{
"https://tao-tech.tistory.com/user_info": {
"username": "tao",
"preferred_language": "ko"
}
}
비공개 클레임 (Private Claim)
비공개 클레임은 사용자 정의 클레임으로, 서버와 클라이언트 사이에 임의로 지정한 정보를 저장합니다.
{
"token_iss": "ACCESS",
"role": "USER"
}
서명 (Signature)
토큰 진위 여부를 확인하고 데이터의 무결성은 보장하는 역할을 합니다.
서명 생성 과정
- `헤더와 페이로드 인코딩` JWT의 헤더와 페이로드를 Base64Url로 인코딩
- `비밀 키 사용` 비밀 키를 사용하여 인코딩된 헤더와 페이로드를 결합한 후 해시 함수를 적용해 서명을 생성
- `서명 추가` 생성된 서명을 JWT의 세 번째 부분(Signature)으로 추가
토큰의 작동 방식
- `로그인 요청` : 사용자가 ID, Password를 입력하여 서버에 로그인 요청을 합니다.
- `사용자 유효성 검증` : 서버는 데이터베이스에 저장된 정보를 통해 사용자의 입력에 대해 유효성을 검증합니다.
- `토큰 생성` : 서버가 사용자의 인증 정보를 검증하고, 검증이 완료되면 해당 사용자에 대한 토큰을 생성합니다. 이 토큰에는 사용자 정보, 만료시간 등이 포함됩니다.
- `토큰 전송` : 서버는 생성된 토큰을 클라이언트에 전송합니다.
- `토큰 저장` : 클라이언트는 전송받은 토큰을 저장합니다. (ex: 브라우저에서는 로컬 스토리지나 세션 스토리지 등에 저장)
- `리소스 요청` : 클라이언트가 서버로 리소스를 요청할 때, Authorization Header를 통해 토큰이 함께 전달됩니다.
- `토큰 유효성 검증` : 서버는 클라이언트로부터 전달받은 토큰을 서버의 비밀키로 검증합니다. 이를 통해, 토큰이 위조되었는지 토큰의 유효기간이 지났는지에 대해 확인할 수 있습니다.
- `응답 전송` : 토큰이 유효할 경우, 서버는 요청에 대한 응답을 클라이언트에게 전송합니다.
토큰의 장단점
장점
- 무상태(Stateless)
- `서버의 부담 감소` 토큰 기반 인증은 서버가 클라이언트의 상태를 기억할 필요가 없기 때문에, 서버 메모리에 세션 정보를 저장하지 않아도 되어 서버의 자원 소모가 줄어들고, 특히 대규모 시스템에서의 부하 분산에 유리합니다.
- `스케일링 용이` 여러 서버에 걸쳐 로드 밸런싱을 쉽게 할 수 있으며, 서버 간 세션 정보를 공유할 필요가 없어 사용자가 어떤 서버에 접속하든 토큰을 사용하여 인증이 가능합니다.
- 분산 시스템 지원
- `마이크로서비스와의 호환성` 토큰은 클라이언트와 서버 간의 통신을 단순화하며, 다양한 마이크로 서비스간에 인증 정보를 쉽게 전달이 가능합니다. 각 서비스는 토큰을 검증하여 사용자 인증 상태를 확인할 수 있습니다.
- 보안성
- `서명 및 암호화` JWT와 같은 토큰은 서명된 정보를 포함하고 있어, 데이터의 무결성을 검증할 수 있습니다. 이를 통해 토큰이 변조되지 않았음을 확인하고, HTTPS와 함께 사용하면 통신의 기밀성과 보안성을 크게 향상시킬 수 있습니다.
- `부가적인 정보 담기` 페이로드(Payload)에 클레임을 포함하여 사용자에 대한 정보(권한, 역할 등)를 저장할 수 있어 서버 측 데이터베이스 조회를 감소시킬 수 있습니다.
- 사용자 경험 개선
- `편리한 인증 관리` 클라이언트가 로그인 한 후 여러 페이지를 탐색할 때, 매번 로그인 정보를 입력할 필요가 없어 사용자 경험이 향상됩니다. 사용자는 연속적인 세션을 통해 더욱 원활한 서비스를 이용할 수 있습니다.
- `다중 장치 지원` 클라이언트는 여러 장치에서 토큰을 사용하여 인증 상태를 유지할 수 있습니다. 예를 들어 모바일과 데스크탑에서 동일한 계정을 사용하면서 로그인 상태를 유지할 수 있습니다.
단점
- 토큰 크기
- `네트워크 오버헤드` JWT와 같은 토큰의 크기는 상대적으로 크며, 페이로드에 포함된 데이터 양에 따라 더욱 커질 수 있습니다. 이는 클라이언트와 서버 간의 통신에서 추가적인 데이터 전송 비용을 발생시킬 수 있습니다.
- 만료 시간 관리
- `갱신 로직 필요` 토큰은 일반적으로 일정 시간 후에 만료되어, 클라이언트는 만료된 토큰을 사용하기 전에 새로운 토큰을 요청해야 합니다. 이를 위해서 토큰 갱신 로직 `Refresh Token`을 구현해야 할 수 있으며, 이 과정에 복잡성이 증가할 수 있습니다.
- 회수의 어려움
- `세션 관리 문제` 사용자가 로그아웃하거나 계정 권한이 변경되었을 때, 해당 토큰을 강제로 만료시키는 것이 어렵습니다. 예를 들어 공격자가 세션을 탈취한 경우, 해당 사용자의 모든 요청이 인증될 수 있어 보안위험이 증가합니다. 이 문제를 해결하기 위해 추가적인 로직이 필요합니다.
- 보안 위험
- `토큰 탈취 위험` 클라이언트 측에 토큰이 저장되므로, 공격자가 이를 탈취할 경우 인증된 사용자로 가장할 수 있습니다. 이를 방지하기 위해서는 HTTPS를 사용하고, 안전한 저장 방법(로컬 스토리지, 쿠키 등)을 고려해야 합니다.
- 구조적인 복잡성
- `정교한 구현 필요` 토큰 기반 인증 방식을 구현할 때, 적절한 보안 프로토콜 및 패턴을 따르는 것이 중요합니다. 구현 과정에서 발생할 수 있는 보안 취약점(CSRF, XSS)에 대한 대비가 필요하며, 잘못된 구현은 시스템 전체의 보안을 저해할 수 있습니다.
토큰 정리
JWT(Json Web Token) 기반 인증은 사용자가 로그인하면 서버가 인증을 확인한 후 클라이언트에게 암호화된 토큰을 발급하여, 이후 요청 시 토큰을 포함시켜 인증 상태를 유지하는 방식입니다.
이 방식은 서버가 클라이언트의 상태를 기억할 필요가 없어 자원 소모가 줄어들고, 마이크로서비스 간의 인증 정보 전달을 용이하게 하며, 사용자 경험을 개선하는 장점이 있지만, 상대적으로 큰 토큰 크기, 만료된 토큰 관리의 복잡성, 사용자가 로그아웃할 때 토큰을 강제로 만료시키기 어려운 점이 있습니다.
그리고 JWT의 보안성은 그 자체로 장점이지만, 개발자가 보안 조치를 소홀히 하거나 잘못된 구현을 했을 때 장점이 단점으로 다가올 수 있어 JWT 기반 인증을 도입할 때는 보안성을 극대화하고 위험을 최소화 할 수 있는 방법을 함께 고려해야 합니다.
세션(Session), 토큰(Token) 기반 인증의 차이점
- 상태 관리
- 세션 인증
- 서버가 클라이언트의 상태를 유지하며, 세션 ID를 통해 클라이언트를 식별합니다. 서버는 세션 정보를 메모리에 저장하므로 상태(Stateful)입니다.
- 토큰 인증
- 서버가 클라이언트의 상태를 기억하지 않으며, 클라이언트가 JWT와 같은 토큰을 통해 인증 상태를 유지합니다. 이 방식은 무상태(Stateless)입니다.
- 세션 인증
- 저장 위치
- 세션 인증
- 세션 정보는 서버에 저장되고, 클라이언트는 세션 ID만 쿠키에 저장합니다.
- 토큰 인증
- 토큰은 클라이언트에 저장되며, 요청 시마다 Authorization Header를 통해 서버로 전송됩니다.
- 세션 인증
- 확장성
- 세션 인증
- 여러 서버에 로드 밸런싱을 적용하기 어려우며, 서버 간 세션 정보를 공유해야 합니다.
- 토큰 인증
- 서버 간 세션 정보를 공유할 필요가 없어, 여러 서버에 걸쳐 쉽게 로드 밸런싱이 가능합니다.
- 세션 인증
- 보안성
- 세션 인증
- 세션 ID가 탈취 될 경우 세션이 유효한 동안 인증이 가능하므로, 세션 관리가 중요합니다.
- 토큰 인증
- JWT의 보안성은 서명 및 암호화에 의존하지만, 클라이언트 측에서 토큰이 저장되므로 토큰 탈취 위험이 존재합니다. 이를 위해 HTTPS를 사용하고 , 안전한 저장방법(로컬 스토리지, 쿠키 등)을 고려해야합니다.
- 세션 인증
- 유효성 관리
- 세션 인증
- 서버에서 세션을 삭제하거나 만료시키면 즉시 세션을 종료할 수 있습니다.
- 토큰 인증
- 토큰의 유효 기간이 만료될 때까지 유효하며, 강제로 만료시키기 어렵습니다. 보통 Refresh Token을 사용하여 갱신합니다.
- 세션 인증
총 정리
세션 기반 인증은 웹 애플리케이션과 보안이 중요한 내부 시스템에서 사용자 경험을 개선하고 보안성을 강화하는 데 유리하며, 짧은 사용 기간과 단일 서버 환경에서 효과적입니다.
토큰 기반 인증은 RESTful API, 모바일 애플리케이션, 마이크로서비스 아키텍처에서 유용하며, 클라이언트 상태를 서버가 기억하지 않고 다양한 장치 간 인증을 지원하고, 여러 외부 서비스와의 통합을 용이하게 하는 장점이 있습니다.
각 인증 방식은 특정 요구 사항에 따라 최적의 선택이 필요합니다.
'Server' 카테고리의 다른 글
GitHub Actions(CI/CD), AWS S3, CodeDeploy 지속적 통합, 배포 자동화 (2) | 2024.12.02 |
---|---|
[AWS] EC2, RDS, ElastiCache 인스턴스 생성부터 배포까지 (4) | 2024.11.28 |
CSR과 SSR의 개념과 차이점 (feat. SPA, MPA) (4) | 2024.09.11 |
REST API, RESTful API란? (2) | 2024.08.30 |