현대의 웹 애플리케이션에서 사용자가 로그인 상태를 유지하고, 장바구니에 상품을 담고, 개인화된 경험을 누리는 것은 당연하게 여겨진다. 그러나 이러한 기능들은 웹의 근간을 이루는 프로토콜에 내재된 것이 아니라, 본래 단순한 문서 검색을 위해 설계된 프로토콜 위에 정교하게 구축된 추가적인 계층이다.
월드 와이드 웹(World Wide Web)의 기반은 하이퍼텍스트 전송 프로토콜(Hypertext Transfer Protocol, HTTP)이다. HTTP의 핵심 개념은 상태 비저장(statelessness)이다. 이는 서버가 수신하는 모든 HTTP 요청을 이전의 어떤 요청과도 관련이 없는 완전히 독립적인 트랜잭션으로 취급한다는 것을 의미한다.
이 개념을 비유하자면, 웹 서버와 상호작용하는 것은 심각한 단기 기억 상실증을 앓는 사람과 대화하는 것과 같다. 모든 문장을 말할 때마다 자신을 다시 소개하고 모든 맥락을 처음부터 제공해야 한다. 이러한 단순성은 본래 문서 중심의 웹을 위한 설계적 특징이었다. 서버가 모든 클라이언트의 세션 상태를 저장할 필요가 없게 함으로써, 확장성과 신뢰성을 향상시켰기 때문이다.
[출처: https://hanamon.kr/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-http-http%EB%9E%80-%ED%8A%B9%EC%A7%95-%EB%AC%B4%EC%83%81%ED%83%9C-%EB%B9%84%EC%97%B0%EA%B2%B0%EC%84%B1/]
하지만 이러한 특성은 현대적인 웹 애플리케이션에 심각한 결과를 초래한다. 예를 들어, 상태 관리 솔루션이 없다면 사용자는 사이트의 모든 페이지에서 매번 로그인해야 하거나, 새로운 상품을 클릭할 때마다 장바구니에 상품을 다시 추가해야 한다. 이는 순수한 상태 비저장 방식이 상호작용이 필수적인 애플리케이션에는 비현실적임을 명확히 보여준다.
이 지점에서 웹 세션 보안이라는 분야 전체가 왜 존재하는지에 대한 근본적인 이해에 도달할 수 있다. 상태 관리는 HTTP 프로토콜의 핵심 기능이 아니라, 그 위에 덧붙여진 '사후 고려 사항(afterthought)'이다. 이로 인해 상태 관리 계층은 공격자들의 본질적이고 주요한 표적이 된다.
이 논리적 흐름은 다음과 같다.
따라서, HTTP를 확장 가능하게 만들었던 바로 그 설계적 선택이 우리가 다루고 있는 근본적인 보안 과제를 창출한 것이다.
쿠키는 상태 비저장의 한계를 극복하기 위한 주요 메커니즘으로 도입되었다. 쿠키는 서버가 사용자의 웹 브라우저로 보내는 작은 데이터 조각으로, 브라우저는 이를 저장했다가 동일한 서버에 후속 요청을 보낼 때 다시 전송한다.
여기서 쿠키(cookies)와 세션(sessions)을 명확히 구분하는 것이 중요하다. 쿠키는 클라이언트 측의 데이터 저장 메커니즘인 반면, 세션은 사용자의 상호작용 기간을 나타내는 서버 측의 개념이다. 세션은 고유 ID로 식별되며, 이 세션 ID는 일반적으로 쿠키 안에 저장된다.
이 두 가지 주요 접근 방식의 근본적인 차이는 인증 데이터가 어디에 저장되는가에 있다. 이 차이점은 보안, 확장성, 구현 복잡성에 지대한 영향을 미친다.
이 방식에서는 사용자를 식별하고 인증하는 데 필요한 모든 데이터가 클라이언트의 브라우저에 있는 쿠키에 직접 저장된다. 여기에는 사용자 ID, 역할, 권한과 같은 민감한 정보나, 이 모든 정보를 자체적으로 포함하고 암호학적으로 서명된 토큰(예: JSON Web Token, JWT)이 포함될 수 있다. 서버는 각 요청에 포함된 쿠키의 정보를 해독하고 검증하기만 하면 되므로, 서버 측에 사용자 세션 상태를 유지할 필요가 없다. 이 '상태 비저장(stateless)' 아키텍처는 서버 구현을 단순화하고 부하를 줄여준다는 장점이 있다. 하지만 이는 중대한 보안 위험을 수반한다. 만약 공격자가 쿠키를 탈취하면(예: XSS 공격 또는 악성코드를 통해), 쿠키 안에 담긴 모든 민감한 인증 정보를 직접 획득하게 되어 즉시 계정을 탈취할 수 있다.
이 방식은 보안을 강화하기 위해 상태 저장을 서버 측으로 옮긴다. 인증 데이터의 핵심은 서버에 안전하게 보관되며, 클라이언트의 브라우저에 저장되는 쿠키에는 오직 임의의 문자열로 구성된 고유 세션 식별자(Session ID)만 포함된다. 이 세션 ID 자체는 아무런 의미가 없는 '키(key)'에 불과하다.
작동 흐름은 다음과 같다
[출처: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Cookies]
이 접근 방식은 훨씬 더 안전한 것으로 간주된다. 민감한 사용자 데이터가 서버를 떠나지 않으며, 공격자가 세션 ID를 탈취하더라도 서버의 세션 저장소에 접근하지 않고는 아무런 의미가 없기 때문이다. 하지만 서버가 모든 활성 세션을 저장하고 관리해야 하므로 서버의 메모리 부하가 높고, 세션 만료 및 저장소 관리가 필요하여 구현이 더 복잡해질 수 있다.
표 1: 쿠키 기반 인증과 세션 기반 인증 비교
| 기능 | "순수" 쿠키 기반 인증 | 세션 기반 인증 |
|---|---|---|
| 데이터 저장 위치 | 모든 인증 데이터가 클라이언트의 브라우저 쿠키에 저장됨. | 인증 데이터는 서버 측에 저장되고, 클라이언트 쿠키에는 참조용 ID만 저장됨. |
| 클라이언트 측 토큰 | 사용자 ID, 역할 등 의미 있는 데이터를 포함함. | 서버의 세션 데이터를 가리키는, 그 자체로는 의미 없는 임의의 세션 ID만 포함함. |
| 보안 프로필 | 쿠키 탈취 시 민감 정보가 바로 노출되어 더 취약함. | 더 안전함. 탈취된 세션 ID는 서버 데이터 없이는 쓸모가 없으며, 민감 정보는 서버에만 존재함. |
| 서버 부하 | 서버가 세션 상태를 유지할 필요가 없어 메모리 부하가 낮음 (Stateless). | 모든 활성 세션을 저장해야 하므로 서버 메모리/저장소 부하가 높음 (Stateful). |
| 구현 복잡성 | 서버 측 세션 관리가 없어 비교적 간단함. | 세션 만료, 저장소 관리, 확장성 고려 등 구현이 더 복잡할 수 있음. |
일반적인 세션 기반 로그인 프로세스는 다음과 같은 단계별 흐름을 따른다.
쿠키는 단순히 이름-값 쌍이 아니라, 보안 제어 장치 역할을 하는 여러 속성을 가지고 있다.
Secure 속성: 이 속성은 쿠키가 암호화된 HTTPS 연결을 통해서만 전송되도록 강제한다. 이는 네트워크 도청 및 세션 하이재킹(session hijacking)에 대한 주요 방어 수단이다.HttpOnly 속성: 이 속성은 document.cookie와 같은 클라이언트 측 자바스크립트가 쿠키에 접근하는 것을 방지한다. 이는 세션 쿠키를 훔치려는 목적의 사이트 간 스크립팅(Cross-Site Scripting, XSS) 공격에 대한 결정적인 방어책이다.SameSite 속성 (Strict, Lax, None): 사이트 간 요청 위조(Cross-Site Request Forgery, CSRF) 공격에 대한 강력한 방어 수단이다. 각 값의 동작 방식은 다음과 같다.Strict: 쿠키는 동일 사이트(same-site) 요청에만 전송된다. 가장 안전하지만, 외부 링크를 통한 기능이 깨질 수 있다.Lax: 현대 브라우저의 기본값이다. 최상위 탐색(예: 링크 클릭) 시에는 쿠키 전송을 허용하지만, 사이트 간 하위 요청(예: 이미지, 폼)에서는 차단한다. 보안과 사용성 사이의 좋은 균형을 제공한다.None: 모든 사이트 간 요청에 쿠키를 전송하도록 허용하지만, 반드시 Secure 속성과 함께 사용되어야 한다. 서드파티 위젯이나 서비스에 필요하다.Domain 및 Path 속성: 이 속성들은 쿠키의 유효 범위를 정의하여, 쿠키가 전송될 도메인과 URL 경로를 제어한다. 이를 너무 광범위하게 설정할 경우, 공유 도메인 내의 덜 안전한 애플리케이션에 쿠키가 노출될 수 있는 보안 위험이 있다.Expires / Max-Age 속성: 쿠키의 수명을 제어한다. 이 속성들이 없는 쿠키는 브라우저가 닫힐 때 삭제되는 "세션 쿠키"이다. 이 속성들을 가진 "영속적인 쿠키"는 브라우저를 다시 시작해도 유지된다.웹 보안 철학의 중요한 변화는 브라우저의 기본 설정이 진화하는 방식에서 엿볼 수 있다. 특히 SameSite=Lax가 표준으로 자리 잡은 것은, 개발자가 보안을 위해 '옵트인(opt-in)'해야 했던 모델에서 특정 기능을 위해 의식적으로 '옵트아웃(opt-out)'해야 하는 모델로의 전환을 의미한다.
과거에는 쿠키가 모든 요청과 함께 전송되어 CSRF가 만연한 위협이었고, 개발자들은 안티-CSRF 토큰을 구현하는 것을 기억해야만 했다. 이에 대응하여 SameSite 속성이 옵트인 방식의 방어책으로 도입되었다. 그러나 브라우저 공급업체들은 개발자들이 항상 이를 기억하는 것에 의존하는 방식이 실패하고 있음을 인지했다. 그들은 SameSite 속성이 없는 쿠키를 Lax로 취급하도록 기본 동작을 변경했다.
이는 이제 CSRF에 대한 보안이 기본 상태가 되었음을 의미한다. 임베디드 콘텐츠와 같이 사이트 간 쿠키 기능이 필요한 개발자들은 이제 명시적으로 SameSite=None; Secure를 선언해야 한다. 이러한 변화는 보안 커뮤니티와 브라우저 제작사들이 전체 웹 생태계의 보안 기준선을 적극적으로 높이고 있으며, 레거시 또는 잘못 구성된 애플리케이션의 공격 표면을 자동으로 줄이고 있음을 시사한다. 이는 '기본적으로 안전한(secure-by-default)' 접근 방식으로의 전환이다.
세션 하이재킹(Session Hijacking)(또는 쿠키 하이재킹)은 유효한 세션을 악용하여 시스템에 대한 무단 접근을 획득하는 행위로 공식적으로 정의된다. 공격자는 사용자의 비밀번호를 훔치는 것이 아니라, 활성화된, 인증된 세션 자체를 훔친다. 이 공격의 핵심은 서버가 사용자를 식별하는 유일한 수단인 세션 토큰(또는 세션 ID)을 탈취하는 것이다.
그 영향은 심각하다. 공격자는 합법적인 사용자가 할 수 있는 모든 행위, 예를 들어 개인 데이터 접근, 금융 거래 수행, 계정 정보 변경 등을 할 수 있다. 특히 현대적인 위협으로서, 세션은 다중 인증(MFA) 확인이 완료된 후에 탈취될 수 있기 때문에 MFA를 우회할 수 있다는 점이 강조되어야 한다.
세션 사이드재킹(Session Sidejacking)은 패킷 스니핑(packet sniffing)에 의존하는 특정 유형의 하이재킹이다. 이 공격은 공격자가 사용자와 서버 간의 네트워크 트래픽을 '엿듣는' 능력에 기반한다.
Cookie 헤더를 찾는다. 과거 많은 사이트들이 로그인 페이지만 HTTPS를 사용하고 이후 페이지에서는 HTTP로 전환하여 바로 이 취약점을 노출시켰다. 공격자는 이 평문 Cookie 헤더에서 sessionid=ab123xyz...와 같은 값을 식별하고 추출한다.Cookie 헤더에 포함된 세션 ID를 확인한다. 서버의 관점에서는 이 ID가 유효한 활성 세션과 일치하므로, 요청이 합법적인 사용자의 것인지 공격자의 것인지 구별할 방법이 없다. 결과적으로 서버는 공격자에게 피해자 계정에 대한 전체 접근 권한을 부여한다.이 공격은 세션 토큰의 소유가 신원을 증명한다는 서버의 신뢰를 악용하는 것이다.
HttpOnly 플래그로 보호되지 않은 경우).
2단계: "스니핑" (쿠키 추출)
브라우저 1에서 대상 웹사이트에 머무는 동안, Cookie-Editor 확장 프로그램 아이콘을 클릭한다.
현재 도메인에 대한 모든 쿠키 목록이 나타난다. 세션 ID를 포함할 가능성이 있는 쿠키(이름은 session, sessionid, JSESSIONID 등일 수 있음)를 찾는다.
이 쿠키를 선택하고 "내보내기(Export)" 버튼을 클릭한다. 클립보드에 JSON 형식으로 내보내는 옵션을 선택한다. 이 행위는 공격자가 암호화되지 않은 네트워크 트래픽에서 쿠키 값을 스니핑하는 것을 시뮬레이션한다.

3단계: 공격자의 시도
브라우저 2("공격자")를 연다. 동일한 대상 웹사이트로 이동한다. 로그인되어 있지 않은 상태인지 확인한다. 공개 페이지나 로그인 프롬프트가 보여야 한다.


이 실습은 세션 기반 시스템의 보안이 세션 토큰의 비밀성에 전적으로 의존한다는 사실을 강력하게 보여준다. 서버는 합법적인 사용자와 공격자 모두 동일한 유효한 토큰을 제시할 경우, 둘을 구별할 본질적인 방법이 없다.
서버의 인증 논리는 "들어오는 요청의 Cookie 헤더에 내 세션 저장소에 존재하고 유효한 세션 ID가 있는가?"라는 단순한 질문에 기반한다. 이 실습은 이 ID가 한 기기/브라우저에서 다른 기기/브라우저로 복사될 수 있음을 보여준다. 공격자의 브라우저가 훔친 ID를 제시하면 서버의 검사를 통과하고, 서버는 해당 요청을 인증된 것으로 처리한다. 이는 서버가 토큰의 소유가 신원을 증명한다고 신뢰한다는 핵심 가정을 드러낸다. 이 공격은 바로 이 가정을 깨뜨림으로써 작동한다. 따라서 전송 중(HTTPS 사용) 및 클라이언트에서(HttpOnly 사용) 토큰의 기밀성과 무결성을 보호하는 것이 왜 가장 중요한지를 명확히 한다.
세션 사이드재킹에 대한 가장 효과적인 단일 방어책은 로그인 페이지만이 아니라 웹사이트 전체에 걸쳐 HTTPS(SSL/TLS)를 강제하는 것이라고 단언할 수 있다.
HTTPS는 헤더를 포함한 전체 HTTP 요청과 응답을 암호화한다. 이는 공격자가 네트워크를 스니핑하더라도 세션 ID가 포함된 Cookie 헤더가 암호화된 무의미한 데이터로 보이기 때문에 쓸모없게 만든다는 것을 의미한다.
필수적인 서버 측 및 애플리케이션 수준의 제어 목록은 다음과 같다.
Secure 및 HttpOnly 플래그를 사용해야 한다. 기본적으로 SameSite=Lax 또는 Strict를 사용한다.Expires/Max-Age): 모든 세션 쿠키에 합리적인 절대 만료 시간을 설정해야 한다. 이는 사용자가 브라우저를 닫지 않더라도 특정 시간이 지나면 세션이 강제로 종료되도록 보장한다.User-Agent 문자열을 확인하는 것도 유사한 접근 방식이지만, 이 또한 쉽게 위조될 수 있다.기술적이지 않은 사용자가 자신을 보호하기 위한 실행 가능한 조언이다.