웹 개발을 하면서 HTTP 통신의 기본 원리를 이해하는 것은 필수적입니다. 특히 상태 비저장(Stateless) 프로토콜인 HTTP에서 사용자 상태를 유지하기 위한 방법과 관련 보안 이슈를 아는 것은 안전한 웹 애플리케이션을 개발하는 데 매우 중요합니다. 이 글에서는 HTTP의 기본 구조와 함께 쿠키, 세션, JWT에 대한 개념과 차이점, 그리고 웹 보안 취약점에 대해 알아보겠습니다.

HTTP 메시지의 구조

HTTP 메시지는 서버와 클라이언트 간에 데이터가 교환되는 방식으로, 크게 두 가지 타입으로 나뉩니다:

  1. Request (요청): 클라이언트가 서버로 전달해 서버의 액션이 일어나게끔 하는 메시지
  2. Response (응답): 요청에 대한 서버의 답변

HTTP 메시지는 ASCII로 인코딩된 텍스트 정보이며 여러 줄로 구성됩니다. 요청과 응답의 구조는 비슷하며 다음과 같은 요소들로 이루어져 있습니다:

HTTP 메시지 구조의 공통 요소

  1. 시작 줄(start-line):

    • 요청의 경우: HTTP 메소드, URL, HTTP 버전 정보
    • 응답의 경우: HTTP 버전, 상태 코드, 상태 텍스트
  2. HTTP 헤더(Headers):

    • 요청 또는 메시지 본문에 대한 메타데이터를 포함
    • 예: Content-Type, User-Agent, Accept 등
  3. 빈 줄(blank line):

    • 헤더와 본문을 구분하는 빈 줄
  4. 메시지 본문(Body):

    • 요청과 관련된 데이터(HTML 폼 콘텐츠 등) 또는 응답 데이터(HTML, JSON, XML 등)
    • 본문의 존재 유무 및 크기는 시작 줄과 HTTP 헤더에 명시됨

시작 줄과 HTTP 헤더를 묶어서 '요청 헤드(head)'라고 부르며, HTTP 메시지의 페이로드는 '본문(body)'이라고 합니다.

쿠키(Cookie)

쿠키는 Stateless한 HTTP 통신의 특성을 극복하기 위한 데이터 조각입니다. 클라이언트나 서버 양측에서 생성 가능하며, 일반적으로 동일한 사이트에 재접속할 때 기존에 요청한 사용자인지를 식별하기 위한 용도로 많이 사용됩니다.

쿠키의 주요 용도

  • 사용자 로그인 상태 유지
  • 사용자 선호 설정 저장
  • 사용자 행동 추적 및 분석

쿠키의 관리 방안

쿠키에는 사용자를 식별할 수 있는 민감한 정보가 포함될 수 있기 때문에 안전한 관리가 필요합니다:

  1. HTTP Only:

    • 서버로 HTTP 요청을 보낼 때만 쿠키를 전송함
    • 브라우저에서는 httpOnly 플래그가 있는 쿠키는 JavaScript를 통해 접근할 수 없음
    • httpOnly 플래그가 없는 쿠키는 브라우저의 JavaScript 코드로 Document.cookie를 통해 내용 확인 가능
  2. Secure:

    • HTTPS 프로토콜로 요청했을 때만 쿠키를 전송함
    • 중간자 공격(MITM)으로부터 쿠키 정보를 보호
  3. SameSite:

    • cross-site 요청에는 쿠키가 포함되지 않도록 강제하는 속성
    • CSRF 공격을 방지하는 데 도움
    • Strict, Lax, None 값을 가질 수 있음

쿠키 헤더

  • Set-Cookie: 서버가 응답을 내려줄 때 포함되는 헤더로, 브라우저에 해당 쿠키를 저장하도록 지시
  • Cookie: 클라이언트가 서버에 요청을 보낼 때 기존에 저장된 쿠키를 함께 전송하는 헤더
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2023 07:28:00 GMT; Secure; HttpOnly

쿠키의 스코프

쿠키의 적용 범위는 DomainPath 속성으로 제한할 수 있습니다:

  1. Domain:

    • 쿠키가 전송될 호스트를 명시
    • 도메인이 명시되면 해당 도메인의 서브도메인들도 항상 포함됨
    • 예: Domain=example.com으로 설정하면 sub.example.com에도 적용됨
  2. Path:

    • Cookie 헤더를 전송하기 위해 요청되는 URL 내에 반드시 존재해야 하는 경로
    • 예: Path=/docs로 설정하면 다음 경로들은 모두 매칭됨:
      • /docs
      • /docs/Web/
      • /docs/Web/HTTP

세션(Session)

세션은 서버(메모리 혹은 DB)에 데이터를 저장하는 방식입니다. 클라이언트는 일반적으로 세션 ID를 쿠키에 저장하고, 서버는 이 ID를 기반으로 세션 데이터를 조회합니다.

세션의 특징

  • 중요 정보는 서버에 저장되어 클라이언트에 노출되지 않음
  • 서버 측 리소스를 사용하기 때문에 사용자가 많을수록 부하가 커짐
  • 서버가 여러 대인 경우 세션 공유를 위한 추가 설정이 필요(세션 클러스터링, Redis 등)

쿠키와 세션의 비교

구분쿠키세션
저장 위치클라이언트(브라우저)서버
보안상대적으로 취약상대적으로 안전
라이프사이클만료 기간 설정 가능서버에서 관리(일반적으로 짧음)
용량 제한브라우저별 제한 있음(~4KB)서버 환경에 따라 다름

JWT(JSON Web Token)

JWT(JSON Web Token)는 Header(JSON), Payload(JSON), Signature(Hash)로 이루어진 데이터를 Base64로 인코딩한 토큰입니다. 토큰 자체에 필요한 모든 정보를 포함하고 있어 서버의 세션 저장소가 필요 없다는 장점이 있습니다.

JWT의 구조

JWT는 점(.)으로 구분된 세 부분으로 구성됩니다:

  1. Header: 토큰 유형과 서명 알고리즘 정보를 포함

    {
      "alg": "HS256",
      "typ": "JWT"
    }
  2. Payload: 클레임(claim) 정보를 포함

    {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022
    }
  3. Signature: 헤더와 페이로드의 인코딩 값을 비밀 키로 해싱하여 생성

    HMACSHA256(
      base64UrlEncode(header) + "." + base64UrlEncode(payload),
      secret
    )

JWT의 장점

  • 서버 측 세션 저장소가 필요 없음(Stateless)
  • 서버 확장성이 좋음(수평적 확장에 용이)
  • 다양한 프로그래밍 언어에서 지원
  • 모바일 애플리케이션에서도 사용하기 편리

JWT의 단점

  • 토큰 크기가 세션 ID보다 큼(네트워크 오버헤드)
  • 토큰에 저장된 정보는 클라이언트에서 볼 수 있음(민감 정보 저장 불가)
  • 일단 발급된 토큰은 만료 전까지 취소하기 어려움

웹 취약점

웹 애플리케이션은 다양한 보안 취약점에 노출될 수 있습니다. 특히 쿠키와 관련된 주요 취약점에 대해 알아보겠습니다.

XSS(Cross-Site Scripting)

XSS는 공격자가 웹 페이지에 악성 스크립트를 삽입하여 사용자의 브라우저에서 실행되게 하는 공격입니다. 이를 통해 쿠키 탈취, 세션 하이재킹 등의 공격이 가능합니다.

XSS 방어 방법

  • 사용자 입력 데이터를 항상 검증하고 이스케이프 처리
  • Content-Security-Policy(CSP) 설정
  • HttpOnly 쿠키 사용으로 JavaScript를 통한 쿠키 접근 차단

CSRF(Cross-Site Request Forgery)

CSRF는 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위(수정, 삭제, 등록 등)를 특정 웹사이트에 요청하게 하는 공격입니다. 주로 쿠키 인증 방식에서 발생하는 취약점입니다.

CSRF 공격 시나리오

  1. 사용자가 취약한 사이트 A에 로그인(쿠키 생성)
  2. 사용자가 악성 사이트 B를 방문
  3. 사이트 B에서 사이트 A로의 요청을 자동으로 전송
  4. 브라우저는 사이트 A 관련 쿠키를 함께 전송
  5. 사이트 A는 유효한 요청으로 인식하고 처리

CSRF 방어 방법

  • CSRF 토큰 사용
  • SameSite 쿠키 속성 설정
  • Referer 확인
  • 중요 작업에 재인증 요구

CORS(Cross-Origin Resource Sharing)

CORS는 브라우저가 보안상의 이유로 다른 출처(도메인, 프로토콜, 포트)의 리소스에 대한 접근을 제한하는 메커니즘입니다. 요청단과 리소스 제공단의 출처가 다를 경우 브라우저에서는 기본적으로 요청을 차단합니다.

CORS 동작 방식

  1. 단순 요청(Simple Request): 특정 조건을 만족하는 요청은 추가 확인 없이 바로 처리됨
  2. 예비 요청(Preflight Request): OPTIONS 메소드를 사용한 사전 요청으로 실제 요청의 허용 여부를 확인

CORS 설정 방법

서버 측에서 적절한 HTTP 헤더를 설정해야 합니다:

  • Access-Control-Allow-Origin: 자원에 접근할 수 있는 출처를 지정
  • Access-Control-Allow-Methods: 허용할 HTTP 메소드 지정
  • Access-Control-Allow-Headers: 허용할 HTTP 헤더 지정
  • Access-Control-Allow-Credentials: 인증 정보(쿠키, HTTP Authentication) 포함 여부
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true

마무리

이 글에서는 HTTP의 기본 개념과 함께 쿠키, 세션, JWT의 차이점, 그리고 웹 보안 취약점에 대해 알아보았습니다. 웹 개발을 할 때는 사용자의 상태를 관리하면서도 보안을 유지하는 것이 중요합니다. 각 인증 방식은 장단점이 있으므로 애플리케이션의 요구사항과 보안 수준에 맞게 적절한 방식을 선택해야 합니다.

특히 쿠키 사용 시에는 HttpOnly, Secure, SameSite 등의 속성을 적절히 설정하고, XSS와 CSRF 같은 공격에 대한 방어책을 마련해야 합니다. 또한 CORS 설정을 통해 안전한 교차 출처 리소스 공유가 가능하도록 해야 합니다.

안전한 웹 애플리케이션 개발을 위해 이러한 HTTP 기본 지식을 잘 이해하고 적용하시기 바랍니다.

참고 자료