내 장바구니에 담긴 물건만 내가 볼 수 있다고 믿고 쇼핑몰에 로그인했는데, 갑자기 다른 사람의 주문 내역이 쭉 보인다면 얼마나 당황스러울까요? 이런 끔찍한 상황은 단순한 화면 오류가 아니라, “이 사용자가 진짜 누구인지(Authentication,인증)” 그리고 “그 사용자에게 이 데이터를 보여줘도 괜찮은지(Authorization,인가)”를 결정하는 로직이 제대로 작동하지 않았다는 증거입니다. 게다가 한 번 로그인하면 페이지를 옮겨도 계속 내 계정으로 머물러 있어야 하는데, 이 ‘로그인 상태 유지’를 책임지는 것이 바로 세션(Session)입니다. 이처럼 누가 누구인지 확인하고, 그 사람에게 무엇을 허용할지를 결정하는 인증·인가의 원리부터, 로그인 상태를 안전하게 관리하는 세션과 쿠키의 비밀까지 알아보도록 하겠습니다.
웹 애플리케이션에서 로그인 버튼을 누르는 순간, 브라우저와 서버는 각자의 역할을 시작합니다.
브라우저는 ‘쿠키’라는 간단한 메모장에 세션 ID와 같은 인증용 식별자를 저장합니다. 이 메모장은 사용자의 기기에 안전하게 보관되며, 이후 동일한 도메인으로 요청을 보낼 때마다 브라우저가 자동으로 서버에 함께 전송합니다.
HttpOnly, Secure, SameSite)을 적절히 설정하면 XSS, CSRF, 중간자 공격으로부터 어느 정도 방어할 수 있습니다. Cookie 주요속성
- Name / Value : 식별자와 값
- Domain / Path : 어느 요청에 포함될 지 범위 지정
- Expires / Max-Age : 쿠키 유효 기간 지정 -> 세션 타임 아웃 설정
- HttpOnly : 자바스크립트 접근 차단 -> XSS 공격 완화
- Secure : HTTPS 연결에서만 전송 -> 중간자 공격 방어
- SameSite : CSRF 방어 정책
서버는 클라이언트가 보낸 세션 ID를 키(Key) 삼아, 내부의 세션 저장소에서 사용자별 상태 정보(프로필, 권한, 로그인 시간 등)를 관리합니다. 세션 저장소는 메모리나 Redis, 데이터베이스 등 어디든 될 수 있고, 다음과 같은 흐름으로 작동합니다:
1. 사용자가 로그인 → 서버가 고유 세션 ID 생성
2. 서버는 세션 저장소에 { sessionId: { userId, roles, ... } } 형태로 저장
3. 브라우저가 이후 요청에 세션 ID 쿠키를 자동 포함
4. 서버는 세션 ID로 사용자를 식별하고, 저장된 상태 정보를 꺼내서 한 번만 로그인해도 계속 인증된 상태 유지
정리
💡 쿠키 : 놀이공원에서 받는 손목 밴드로 "입장권이 유효하다"는 표시
세션 : 그 손목밴드를 보고 "이 손목밴드는 VIP 티켓이야" 혹은 "어린이용 입장권이야" 같은 상세 정보를 관리
인증은 "당신은 누구인가요"라는 질문에 답하는 과정입니다. 아이디, 비밀번호,OTPm 소셜 로그인 등 다양한 방법으로 사용자의 신원을 검증하죠, 인증이 제대로 작동하지 않으면 악의적인 사용자가 타인의 계정에 접근해 개인정보를 탈취하거나 불법 행위를 할 수 있습니다.

인증하는 방식에는 크게 세션(Session), JWT 방식이 있습니다.
POST /login with {username, password}Set-Cookie: sessinId=XYZ; HttpOnly 응답Cookie: sessionId=XYZ 포함💡 비밀번호는 해시 (SHA-256, bcrypt 등)로 저장하고, 로그인 시 비교해야 안전합니다.
Post /login with {username, password}Authorization 헤더 (Bearer <token>)에 토큰 전달HttpOnly, Secure)에 토큰 저장Authorization: Bearer <token> 헤더 포함💡 JWT는 무상태(stateless)로 확장성이 뛰어나지만, 탈취 시 위험하므로
Secure,HttpOnly속성과 짧은 만료 시간을 권장합니다.
인가란 사용자가 '어떤 행동'을 할 수 있는지를 결정하는 과정입니다. 한 집에 손님을 초대하면 현과문을 열어주는 것이 인증이라면, 집 안 어디까지 들어갈 수 있는지를 정하는 것이 인가입니다. 예를 들어, 손님에게 거실은 모두 개방하지만, 침실이나 금고가 있는 방은 금지 구역으로 설정할 수 있습니다. 인가를 설정하는 방법에는 역할 기반(RBAC), 속성 기반 (ABAC), 정책 기반 (Policy-Based Access Contorl) 이 있습니다.
각각의 특징에 대해서 한 번 알아볼까요?
역할기반 인가는 회사 조직도처럼 사람마다 역할(role)을 부여하는 방식입니다. 예를 들면 관리자(Admin)은 모든 메뉴에 접속이 가능하고, 일반 사용자 (User) 는 내 정보만 조회 가능하도록 하는 거죠. 설계가 단순하고 이해하기 쉽다는 장점은 있지만 역할이 많이질 수록 관리가 복잡해지는 단점이 있습니다.
속성기반 인가는 사용자, 리소스, 환경의 속성(Attribute)을 조합해 권한을 결정합니다.
예를 들면 나이는 18세 이상이면서 구독 등급은 프리미엄인 사용자만 동영상 시청 가능 이렇게 설정하는 거죠. 보통 조건문 형태로 코드나 미들웨어 안에 직접 구현 되는 경우가 많습니다. ABAC는 세밀한 정책 운영이 가능하지만 정책 작성과 유지보수가 다소 까다로울 수 있습니다.
정책기반 인가는 중앙 정책 엔진 (Policy Engine)을 두고, 선언형(Declarative) 규칙을 정의해 런타임에 평가합니다. 예를 들면 휴가 중인 직원은 업무 시스템 접근 불가와 같은 동적인 규칙을 적용하는데요, 코드 수정 없이 수정 가능하고 중앙에서 일관된 정책을 관리, 버전 관리에는 뛰어나지만 정책 엔진 도입과 학습에 시간이 필요하게 됩니다.
- id: forbid_on_leave
description: "휴가 중인 직원은 시스템 접근 금지"
target:
attributes:
user.status: "on_leave"
effect: "deny"
💡 작은 프로젝트나 단순 서비스라면 RBAC을, 다양한 조건과 복잡한 요구사항이 있으면 ABAC나 , 정책 기반 방식을 고려해야합니다.
웹 서비스의 세션은 사용자 경험을 매끄럽게 하는 중요한 기능이지만, 이를 노리는 다양한 공격 기법이 있습니다. 네 가지 주요 세션 공격과 대응 방안에 대해서 알아보겠습니다.
공격자가 미리 발급받은 세션 Id를 피해자에게 전달하여, 피해자가 로그인하면 공격자가 같은 세션을 통해 접근.
대응 방안
1. 로그인 성공 시 기존 세션을 무효화하고 항상 새로운 세션 ID를 발급합니다.
2. SameSite=Lax 또는 Strict로 외부 사이트에서 쿠키가 전송되지 않도록 설정합니다.
공격자가 네트워크 스니핑, XSS 등을 통해 사용자의 세션 쿠키를 훔쳐서, 그 쿠키를 사용해 로그인 우회
대응 방안
1. HttpOnly 속성으로 자바스크립트가 쿠키에 접근하지 못하도록 차단하여 XSS 공격을 원화합니다.
2. Secure 속성으로 HTTPS 연결에서만 쿠키가 전송되게 합니다.
3. Content Security Policy(CSP)와 철저한 입력 검증으로 XSS 근본 방어를 강화합니다.
공격자가 이전에 가로챈 세션 ID나 요청 데이터를 재전송하여 세션을 재 사용.
예) 로그아웃 이후에도 동일한 요청을 반복하면 여전히 유효한 세션으로 인식 될 수 도 있음
대응 방안
1. 토큰 일회용성(Nonce) 을 도입해, 각 요청에 고유 토큰을 포함하고 검증 후 무효화합니다.
2. 세션 사용 이력을 기록하고, 예기치 않은 재전송 요청이 감지되면 세션을 종료합니다.
공격자가 공개 Wi-fi같은 안전하니 않은 네트워크 패킷 스니핑 도구를 사용해 세션 쿠키를 가로채로 이를 악용
대응 방안
1. 모든 트랙픽을 HTTPS로 암호화하여 중간자 (Main-in-the-Middle) 공격을 방지합니다.
2. 세션 타임아웃(유효 시간)을 짧게 설정하여, 탈취된 세션을 사용할 수 있는 시간을 최소화 합니다.
💡 중요한 API호출 (환전, 결제 등)에는 재인증(비밀번호 재입력, OTP)을 요구해 보안을 한층 강화하세요.
전통적인 세션 기반 인증은 서버에 사용자 상태를 저장하고 관리하기 때문에, 서버 스케일링 (서버 추가 확장)이 어려울 수 있습니다. 특히 마이크로서비스 아키텍처나 서버리스 환경에서는 무상태(stateless) 인증이 더 유연하죠. 이때 등장한 것이 바로 JWT입니다. JWT는 서버가 상태를 저장하지 않아도, 자체적으로 사용자 정보를 담은 토큰을 클라이언트에 보내고, 매 요청에 그 토큰이 포함되어 인증 정보를 검증합니다.
JWT는 세 부분으로 구성된 문자열입니다.
HEADER.PAYLOAD.SIGNATURE
typ: JWT)과 서명 알고리즘 (alg: HS256 등 ) 정보를 담고 있습니다.{
"alg": "HS256",
"typ": "JWT"
}
sub(주제, 사용자 ID), iat(발급 시간), exp (만료 시간), roles (권한){
"sub": "user123",
"iat": 1615123456,
"exp": 1615127056,
"roles": ["User","Admin"]
}
1.클라이언트가 자격 증명(아이디·비밀번호)을 서버에 전송합니다.
2. 서버는 검증 후, 페이로드에 클레임을 담아 JWT를 생성합니다.
3. 서버는 JWT를 클라이언트에 응답으로 전달합니다(Authorization 헤더 또는 응답 바디).
4. 클라이언트는 JWT를 로컬스토리지나 안전한 쿠키에 저장합니다.
5. 이후 요청 시, 클라이언트는 Authorization: Bearer <JWT> 헤더를 포함하여 요청합니다.
6. 서버는 토큰 서명과 만료 시간을 검증한 뒤, 페이로드의 클레임으로부터 사용자 정보를 추출하여 인증을 수행합니다.
장점:
단점:
💡 JWT를 안전하게 사용하려면, 토큰 저장 위치(HttpOnly 쿠키 권장), 짧은 만료 시간, 리프레시 토큰, HTTPS 적용을 꼭 고려하세요.