HTTP 헤더 구조
1. 개요
1. 개요
HTTP 헤더는 HTTP 요청과 응답 메시지의 구성 요소로, 클라이언트와 서버 간에 전송되는 메타데이터를 담는다. 이 메타데이터는 메시지 본문(HTTP 바디)에 대한 설명, 클라이언트의 능력, 서버의 상태, 캐싱 지시, 보안 정책 등을 포함하여 통신의 핵심적인 제어 정보를 제공한다. 헤더는 메시지의 처리 방식을 결정하는 데 필수적인 역할을 한다.
HTTP 헤더는 이름과 값의 쌍으로 구성되며, 콜론(:)으로 구분된다. 이들은 메시지의 시작 줄(요청라인 또는 상태라인) 바로 다음에 위치하며, 빈 줄로 끝나 메시지 본문과 구분된다. 헤더의 존재로 인해 같은 HTTP 프로토콜을 사용하더라도 다양한 형태의 데이터 교환과 복잡한 상호작용이 가능해진다.
HTTP/1.1 명세에서는 헤더를 목적에 따라 일반 헤더, 요청 헤더, 응답 헤더, 엔터티 헤더로 분류한다. 시간 정보를 나타내는 Date, 연결 관리를 위한 Connection과 같은 헤더는 일반 헤더에 속한다. 클라이언트가 서버에 자신의 정보를 알리는 User-Agent나 선호하는 언어를 지정하는 Accept-Language는 요청 헤더의 예시이다. 서버의 상태를 알리는 Server 헤더나 응답 코드를 보완하는 Location 헤더는 응답 헤더에 해당한다. 전송되는 데이터(엔터티) 자체의 정보, 예를 들어 타입(Content-Type)이나 길이(Content-Length)를 설명하는 헤더는 엔터티 헤더이다.
HTTP 헤더는 웹의 성능, 보안, 기능성에 지대한 영향을 미친다. 적절한 캐싱 헤더 설정은 네트워크 트래픽을 줄이고 사용자 경험을 향상시키며, 보안 헤더는 XSS나 스니핑과 같은 공격으로부터 사용자를 보호한다. HTTP/2와 HTTP/3에서는 헤더 필드를 압축하여 전송 효율을 극대화하는 HPACK 및 QPACK과 같은 메커니즘이 도입되었다.
2. HTTP 헤더의 기본 구조
2. HTTP 헤더의 기본 구조
HTTP 헤더는 HTTP 메시지의 구성 요소로, 메시지 본문 앞에 위치하여 메시지에 대한 메타데이터를 제공한다. 헤더는 클라이언트와 서버 간의 통신에서 요청과 응답의 성격, 처리 방법, 콘텐츠 정보 등을 정의하는 역할을 한다.
HTTP 헤더는 하나 이상의 헤더 필드로 구성된다. 각 헤더 필드는 다음과 같은 기본 형식을 따른다.
```
필드-이름: 필드-값
```
필드-이름은 대소문자를 구분하지 않는 문자열이며, 필드-값은 해당 헤더의 의미에 따라 다양한 형식을 가진다. 예를 들어, 콘텐츠의 유형을 나타내는 Content-Type 헤더는 text/html; charset=UTF-8과 같은 값을 가질 수 있다. 여러 개의 헤더 필드는 캐리지 리턴과 라인 피드(CRLF, \r\n)로 구분되어 연속적으로 나열된다.
헤더 영역의 끝은 빈 줄(연속된 두 개의 CRLF, \r\n\r\n)로 표시된다. 이 빈 줄은 헤더와 메시지 본문을 구분하는 경계선 역할을 한다. 모든 헤더 필드가 전송된 후 빈 줄이 오면, 그 다음부터는 메시지의 실제 데이터인 본문이 시작된다. 이 구조는 HTTP 요청과 응답 모두에 동일하게 적용된다.
구성 요소 | 설명 | 예시 |
|---|---|---|
시작 줄 |
| |
헤더 필드 | 메시지에 대한 메타데이터. |
|
빈 줄 | 헤더의 끝을 나타내는 구분자. | `\r ` (보이지 않음) |
메시지 본문 | 전송할 실제 데이터. 요청 본문은 선택 사항이다. |
|
2.1. 헤더 필드 형식
2.1. 헤더 필드 형식
HTTP 헤더 필드는 "필드 이름: 필드 값"의 기본 형식을 따른다. 필드 이름은 대소문자를 구분하지 않는 토큰으로 구성되며, 필드 값은 필드 이름 뒤에 콜론(':')과 공백(옵션)을 두고 기술한다. 필드 값은 필드의 종류에 따라 다양한 구문을 가질 수 있다. 예를 들어, Content-Type 헤더의 값은 'text/html; charset=UTF-8'과 같이 미디어 타입과 매개변수로 구성된다.
헤더 필드는 여러 줄에 걸쳐 작성될 수 있으며, 이때 연속되는 줄은 공백(스페이스 또는 탭)으로 시작해야 한다. 이를 '줄 접기'라고 한다. 그러나 현대의 HTTP/2와 HTTP/3에서는 이진 프레임을 사용하여 헤더를 전송하므로, 텍스트 기반의 줄 접기 방식은 더 이상 사용되지 않는다.
구성 요소 | 설명 | 예시 |
|---|---|---|
필드 이름 | 헤더의 종류를 식별하는 이름. 대소문자 구분 없음. |
|
구분자 | 필드 이름과 값을 구분하는 콜론(':'). |
|
필드 값 | 해당 헤더의 구체적인 값. |
|
하나의 HTTP 메시지에는 동일한 이름의 헤더 필드가 여러 개 존재할 수 있다. 이 경우, 그 의미는 헤더 필드에 따라 다르게 해석된다. 예를 들어, 여러 개의 Set-Cookie 헤더는 각각 별도의 쿠키를 설정하지만, X-Forwarded-For 헤더처럼 쉼표로 연결된 값들을 하나의 헤더로 합쳐서 보내는 것이 일반적이다.
2.2. 헤더 구분 기호
2.2. 헤더 구분 기호
HTTP 메시지에서 헤더 필드와 본문을 구분하는 데 사용되는 기호는 빈 줄(Empty Line)이다. 정확히는 캐리지 리턴과 라인 피드로 구성된 CRLF(Carriage Return Line Feed) 시퀀스가 두 번 연속으로 등장하는 부분, 즉 \r\n\r\n이 구분자 역할을 한다.
이 빈 줄은 HTTP 메시지의 구조에서 필수적인 요소이다. 요청이나 응답 메시지는 시작 줄(Start-Line), 헤더(Header), 본문(Body)의 세 부분으로 구성되며, 헤더의 끝을 알리고 본문의 시작을 표시하는 것이 바로 이 구분 기호이다. 만약 메시지에 본문이 존재하지 않더라도, 헤더의 끝을 명시적으로 나타내기 위해 빈 줄은 반드시 존재해야 한다. 이 규칙은 HTTP/1.1 명세(RFC 7230)에 정의되어 있다.
구분 기호의 처리 방식은 다음과 같다.
상황 | 설명 |
|---|---|
본문이 있는 메시지 | `\r \r ` 이후의 모든 데이터가 메시지 본문으로 해석된다. Content-Length 헤더나 Transfer-Encoding 헤더는 본문의 길이 또는 형식을 정의한다. |
본문이 없는 메시지 (예: GET 요청) | 헤더 블록 끝에 `\r \r `이 위치하며, 그 뒤에는 추가 데이터가 없다. |
스트리밍 또는 청크 전송 |
|
프로그래밍적으로, 클라이언트나 서버는 네트워크 스트림에서 데이터를 읽으면서 \r\n\r\n 시퀀스를 찾아 헤더 파싱을 중단하고 본문 처리를 시작한다. 이 구분 기호를 올바르게 처리하지 못하면 메시지를 잘못 해석하여 프로토콜 오류가 발생할 수 있다.
3. 헤더의 종류
3. 헤더의 종류
HTTP 헤더는 그 기능과 사용되는 맥락에 따라 네 가지 주요 범주로 분류된다. 이 분류는 RFC 2616 및 RFC 7231과 같은 HTTP 명세에 정의되어 있으며, 각 헤더가 HTTP 요청과 HTTP 응답 메시지의 어느 부분에서 사용될 수 있는지를 규정한다.
첫 번째는 일반 헤더이다. 이 헤더들은 요청과 응답 메시지 모두에서 사용될 수 있으며, 메시지 전체에 적용되는 정보를 담는다. 대표적인 예로는 메시지의 날짜와 시간을 나타내는 Date, 연결 상태를 제어하는 Connection, 그리고 캐싱 동작을 지시하는 Cache-Control 헤더 등이 있다. 이 헤더들은 특정 요청이나 응답에 국한되지 않는 일반적인 정보를 전달한다.
두 번째와 세 번째는 각각 요청 헤더와 응답 헤더이다. 요청 헤더는 클라이언트가 서버로 보내는 요청 메시지에서만 사용되며, 클라이언트의 정보나 요청의 구체적인 조건을 서버에 알린다. 예를 들어, User-Agent는 클라이언트 소프트웨어(브라우저)를 식별하고, Accept는 클라이언트가 처리할 수 있는 콘텐츠 유형을, Authorization은 인증 자격 증명을 포함한다. 반대로 응답 헤더는 서버가 클라이언트에게 보내는 응답 메시지에서만 사용된다. 서버의 정보나 응답에 대한 추가 지시를 제공하며, Server 헤더는 서버 소프트웨어를 식별하고, Set-Cookie는 클라이언트에 쿠키를 설정하며, 다양한 상태 코드와 함께 사용되는 Location 헤더는 리디렉션 목적지를 가리킨다.
마지막 범주는 엔터티 헤더이다. 이 헤더들은 요청 또는 응답 메시지의 본문(엔터티 바디)에 포함된 리소스 자체에 대한 메타데이터를 설명한다. 콘텐츠의 유형, 길이, 언어, 마지막 수정 시간 등을 나타낸다. 주요 예시로는 콘텐츠의 미디어 타입을 정의하는 Content-Type, 본문 데이터의 크기를 바이트 단위로 표시하는 Content-Length, 그리고 리소스가 마지막으로 수정된 시간을 알리는 Last-Modified 헤더가 있다. HTTP/1.1에서는 이 용어가 사용되었으나, 이후 명세에서는 "표현 헤더"라는 용어로 개념이 진화하기도 했다[1].
3.1. 일반 헤더
3.1. 일반 헤더
일반 헤더는 HTTP 요청과 HTTP 응답 메시지 모두에서 사용될 수 있는 헤더 필드이다. 이 헤더들은 메시지의 전송 자체와 관련된 정보를 제공하며, 특정 요청이나 응답의 콘텐츠와는 직접적인 연관이 없다. 일반 헤더의 주요 역할은 메시지의 날짜, 연결 관리, 캐싱 지시 등의 통신 매개변수를 제어하는 것이다.
주요 일반 헤더 필드로는 다음과 같은 것들이 있다.
헤더 필드 | 설명 |
|---|---|
| 메시지가 생성된 날짜와 시간을 나타낸다. |
| 현재 연결에 대한 옵션을 관리한다. 예를 들어, |
| |
| HTTP/1.0과의 하위 호환성을 위해 남아 있는 헤더로, 주로 |
| 메시지 본문 이후에 트레일러 헤더 필드가 올 것임을 나타낸다. |
| 사용자에게 안전한 방식으로 엔터티 본문을 전송하기 위해 사용되는 인코딩 형식을 지정한다[3]. |
| 클라이언트가 서버에 다른 프로토콜로 업그레이드하도록 제안할 수 있다. |
|
일반 헤더는 클라이언트와 서버 간의 통신 흐름을 관리하는 데 필수적이다. 예를 들어, Cache-Control 헤더는 중간 프록시나 브라우저 캐시가 응답을 저장하고 재사용하는 방식을 결정하며, Connection 헤더는 TCP 연결을 유지할지 닫을지 제어하여 네트워크 효율성에 영향을 미친다. 이러한 헤더들은 애플리케이션 데이터를 운반하는 메시지의 '운송 수단'에 대한 메타데이터를 제공한다고 볼 수 있다.
3.2. 요청 헤더
3.2. 요청 헤더
요청 헤더는 클라이언트가 서버에게 요청을 보낼 때 사용하는 헤더 필드이다. 이 헤더들은 요청의 컨텍스트를 정의하고, 클라이언트의 능력, 선호도, 요청 대상에 대한 추가 정보를 서버에 제공하는 역할을 한다. 주로 HTTP 메서드와 함께 사용되며, 서버가 요청을 적절히 처리하고 최적의 응답을 생성할 수 있도록 돕는다.
요청 헤더는 크게 몇 가지 범주로 나눌 수 있다. 첫째, 요청 자체에 대한 정보를 제공하는 헤더들이다. 대표적으로 User-Agent는 요청을 보내는 클라이언트 소프트웨어(브라우저, 운영체제 등)의 식별 정보를 담는다. Accept 헤더는 클라이언트가 이해할 수 있는 콘텐츠 유형(MIME 타입)을, Accept-Language는 선호 언어를, Accept-Encoding은 선호 압축 방식을 서버에 알려준다. 이를 통해 서버는 콘텐츠 협상을 수행하여 가장 적합한 형식의 응답을 반환할 수 있다.
둘째, 요청의 조건을 지정하거나 캐싱 동작을 제어하는 헤더들이 있다. If-Modified-Since나 If-None-Match와 같은 조건부 요청 헤더는 서버 리소스의 특정 버전(수정 시간이나 ETag 값)을 기준으로 요청을 제한한다. 이는 불필요한 데이터 전송을 줄이고 캐시 효율성을 높이는 데 기여한다. Cache-Control 헤더의 no-cache나 max-age 같은 지시어를 요청에 포함시켜 클라이언트 측 캐시의 동작을 명시적으로 제어할 수도 있다.
셋째, 요청 대상에 대한 정보를 제공하는 헤더도 포함된다. Host 헤더는 요청이 전송되는 호스트와 포트 번호를 지정하며, 하나의 IP 주소에서 여러 도메인이 호스팅되는 가상 호스팅 환경에서 필수적이다. Referer 헤더는 현재 요청을 유발한 이전 웹 페이지의 주소를 나타낸다. Authorization 헤더는 서버의 보호된 리소스에 접근하기 위한 자격 증명(예: 베어러 토큰)을 포함한다.
헤더 필드 예시 | 주요 역할 |
|---|---|
클라이언트 애플리케이션 식별 | |
콘텐츠 협상 | |
조건부 요청(캐시 검증) | |
요청 대상 호스트 지정 | |
인증 자격 증명 전송 |
3.3. 응답 헤더
3.3. 응답 헤더
응답 헤더는 서버가 클라이언트에게 요청에 대한 결과를 전달할 때 사용하는 헤더이다. 이 헤더들은 요청의 처리 상태, 서버 정보, 응답 본문에 대한 메타데이터 등을 포함하여 클라이언트가 응답을 올바르게 해석하고 처리할 수 있도록 돕는다.
주요 응답 헤더로는 상태 코드를 나타내는 Status Code와 상태 메시지를 포함하는 Server, 응답 생성 시간을 알려주는 Date, 응답 본문의 MIME 타입을 지정하는 Content-Type, 본문의 길이를 바이트 단위로 알려주는 Content-Length 등이 있다. 또한, 클라이언트가 특정 리소스를 캐시할 수 있는 기간을 지정하는 Cache-Control과 Expires 헤더, 리소스가 이동된 경우 새로운 위치를 알려주는 Location 헤더, 인증이 필요한 리소스에 접근 시 필요한 인증 방식을 알리는 WWW-Authenticate 헤더도 중요한 응답 헤더에 속한다.
다음은 몇 가지 대표적인 응답 헤더의 예시와 용도를 정리한 표이다.
헤더 필드 | 설명 | 예시 값 |
|---|---|---|
| 요청을 처리한 서버 소프트웨어의 정보 |
|
| 응답 본문의 미디어 타입과 문자 인코딩 |
|
| 클라이언트와 중간 캐시 서버에 대한 캐시 지시어 |
|
| 서버에서 클라이언트에게 쿠키를 설정할 때 사용 |
|
이러한 응답 헤더들은 클라이언트와 서버 간의 효율적인 통신을 보장하고, 캐싱, 세션 관리, 콘텐츠 협상 등 다양한 부가 기능을 구현하는 데 필수적인 역할을 한다.
3.4. 엔터티 헤더
3.4. 엔터티 헤더
엔터티 헤더는 HTTP 메시지의 본문, 즉 엔터티 바디에 포함된 리소스 자체에 대한 메타데이터를 설명한다. 이 헤더들은 요청과 응답 메시지 모두에서 사용될 수 있으며, 전송되는 데이터의 특성, 형식, 크기, 수정 시간 등을 나타낸다. 엔터티 헤더는 리소스의 표현(Representation)에 관한 정보를 제공하여, 클라이언트가 콘텐츠를 어떻게 해석하고 처리해야 하는지 결정하는 데 도움을 준다.
주요 엔터티 헤더 필드로는 Content-Type, Content-Length, Content-Encoding, Content-Language, Last-Modified 등이 있다. Content-Type 헤더는 엔터티 바디의 미디어 타입(예: text/html, application/json)을 명시한다. Content-Length는 바디의 크기를 바이트 단위로 나타내어 메시지의 끝을 판단하는 데 사용된다. Content-Encoding은 적용된 압축 방식(예: gzip, deflate)을, Content-Language는 콘텐츠가 대상으로 하는 자연어를 나타낸다. Last-Modified는 서버에서 해당 리소스가 마지막으로 수정된 날짜와 시간을 제공한다.
이러한 헤더들은 캐싱 메커니즘과 밀접한 관련이 있다. 예를 들어, Last-Modified 헤더는 클라이언트가 이후 요청 시 If-Modified-Since 조건부 요청 헤더를 통해 캐시 유효성을 재확인하는 데 사용된다. 마찬가지로, Content-Type에 지정된 문자 인코딩 정보는 브라우저가 페이지를 올바르게 렌더링하는 데 필수적이다. 엔터티 헤더는 HTTP/1.1 명세에서 정의되었으나, HTTP/2와 HTTP/3에서도 그 의미와 기능은 유지되며, 메시지 프레이밍 방식만 변화했다.
4. 주요 HTTP 헤더 필드
4. 주요 HTTP 헤더 필드
HTTP 헤더는 클라이언트와 서버 간의 통신에서 메타데이터를 전달하는 역할을 한다. 주요 헤더 필드는 그 기능에 따라 콘텐츠 처리, 캐싱, 인증, 연결 관리 등 여러 범주로 나뉜다.
콘텐츠 관련 헤더는 전송되는 데이터 자체의 정보를 설명한다. Content-Type 헤더는 데이터의 미디어 타입(예: text/html, application/json)을 명시하여 클라이언트가 올바르게 해석하도록 돕는다. Content-Length는 메시지 본문의 크기를 바이트 단위로 나타내며, Content-Encoding은 사용된 압축 방식(예: gzip, deflate)을 알려준다. Accept와 Accept-Encoding 같은 요청 측 헤더는 클라이언트가 선호하는 콘텐츠 타입과 압축 방식을 서버에 알리는 역할을 한다.
쐐싱 관련 헤더는 네트워크 효율성을 높이는 데 핵심적이다. 서버는 Cache-Control 헤더를 통해 응답을 캐시할 수 있는 지시사항(예: max-age, no-cache, public)을 제공한다. ETag는 리소스의 특정 버전을 식별하는 유일한 식별자로, 클라이언트가 이후 If-None-Match 헤더에 이 값을 담아 요청하면, 리소스가 변경되지 않았을 때 서버는 본문 없이 304 Not Modified 상태 코드로 응답할 수 있다. Last-Modified와 If-Modified-Since도 비슷한 조건부 요청에 사용된다.
인증 및 보안, 연결 관리 헤더는 통신의 안전성과 지속성을 담당한다. Authorization 헤더는 클라이언트가 서버에 인증 정보(예: Bearer 토큰)를 제출할 때 사용되며, 서버는 WWW-Authenticate로 인증 방식을 요구할 수 있다. Connection 헤더는 특정 연결에 대한 옵션을 제어하며, HTTP/1.1에서 지속 연결을 관리하는 데 중요하다. Host 헤더는 하나의 서버 IP 주소가 여러 도메인을 호스팅할 때 요청된 호스트명을 지정하는 필수 헤더이다.
헤더 범주 | 주요 헤더 필드 예시 | 주요 기능 |
|---|---|---|
콘텐츠 관련 |
| 데이터 형식, 크기, 클라이언트 선호도 명시 |
캐싱 관련 |
| 캐시 유효기간 설정, 조건부 요청 지원 |
인증 및 보안 |
| 사용자 인증 정보 전달 및 요구 |
연결 관리 |
| 연결 옵션 제어, 가상 호스팅 지원 |
4.1. 콘텐츠 관련 헤더
4.1. 콘텐츠 관련 헤더
콘텐츠 타입 헤더는 전송되는 데이터의 미디어 유형을 지정한다. 예를 들어, text/html; charset=UTF-8은 HTML 문서이며 문자 인코딩이 UTF-8임을 나타낸다. 이 헤더는 클라이언트가 데이터를 올바르게 해석하고 렌더링하는 데 필수적이다.
콘텐츠 길이 헤더는 메시지 본문의 크기를 바이트 단위로 명시한다. 이는 특히 POST 요청이나 응답에서 연결 종료 시점을 판단하는 데 사용된다. 콘텐츠 인코딩 헤더는 본문 데이터가 gzip이나 deflate와 같은 방식으로 압축되었음을 알린다.
헤더 필드 | 설명 | 예시 값 |
|---|---|---|
데이터의 미디어 유형(MIME 타입)과 선택적 문자셋을 지정 |
| |
메시지 본문의 정확한 크기(바이트) |
| |
본문에 적용된 압축 방식 |
| |
대상 청중을 위한 자연 언어 |
| |
반환된 데이터에 대한 대체 위치를 제공 |
|
콘텐츠 언어 헤더는 문서가 어떤 언어로 되어 있는지를 나타내며, 다국어 지원 사이트에서 중요하다. 콘텐츠 위치 헤더는 요청에 대한 응답으로 반환된 리소스의 실제 위치가 요청된 URL과 다를 때 사용된다[4].
4.2. 캐싱 관련 헤더
4.2. 캐싱 관련 헤더
캐싱 관련 헤더는 웹 캐시의 동작을 제어하여 네트워크 대역폭을 절약하고 서버 부하를 줄이며 사용자 경험을 향상시키는 역할을 한다. 이 헤더들은 리소스의 신선도(Freshness)와 유효성(Validation)을 관리하는 규칙을 클라이언트와 서버 간에 전달한다. 주요 목표는 불필요한 데이터 전송을 방지하고, 캐시에 저장된 리소스의 최신성을 보장하는 것이다.
캐싱 정책을 정의하는 핵심 헤더는 다음과 같다.
헤더 필드 | 방향 | 주요 역할 |
|---|---|---|
요청/응답 | 캐싱 지시자를 지정하는 가장 강력하고 일반적인 헤더. | |
응답 | 리소스가 만료되는 절대적인 날짜/시간을 지정. Cache-Control의 | |
응답 | 리소스의 버전을 식별하는 불투명한 검증자(Validator). 주로 If-None-Match 요청 헤더와 함께 사용됨. | |
응답 | 리소스가 서버에서 마지막으로 수정된 날짜/시간. 주로 If-Modified-Since 요청 헤더와 함께 사용됨. |
캐싱 흐름은 조건부 요청(Conditional Request)을 통해 이루어진다. 클라이언트가 캐시에 저장된 리소스를 재사용하려 할 때, Cache-Control: max-age=0이 설정되었거나 캐시가 신선하지 않다고 판단하면, 서버에 유효성 재검증 요청을 보낸다. 이때 캐시된 리소스의 ETag 값을 If-None-Match 헤더에 담거나, Last-Modified 값을 If-Modified-Since 헤더에 담아 요청한다. 서버는 이 값을 검사하여 리소스가 변경되지 않았다면 본문 없이 304 Not Modified 상태 코드로 응답하고, 변경되었다면 새로운 리소스와 함께 200 OK로 응답한다.
Cache-Control의 공용 캐시(Public Cache)와 사적 캐시(Private Cache) 제어도 중요하다. public 지시자는 응답이 어떤 캐시에도 저장될 수 있음을 의미하며, private 지시자는 응답이 특정 사용자(예: 브라우저 캐시)만을 위한 것이므로 공유 캐시(예: 프록시 서버)에 저장되어서는 안 됨을 나타낸다. 또한 no-cache는 캐시 저장은 허용하지만, 사용 전 반드시 서버에 재검증을 요구해야 함을 의미하며, no-store는 어떠한 형태로도 캐시에 저장하는 것을 완전히 금지한다.
4.3. 인증 및 보안 헤더
4.3. 인증 및 보안 헤더
인증 관련 헤더는 클라이언트의 신원을 확인하고 접근 권한을 부여하는 데 사용된다. 대표적인 헤더로는 Authorization과 WWW-Authenticate가 있다. 클라이언트가 보호된 자원을 요청할 때 서버는 401 Unauthorized 응답과 함께 WWW-Authenticate 헤더를 보내어 필요한 인증 방식을 알린다. 이후 클라이언트는 자격 증명(예: 사용자명과 비밀번호)을 Authorization 헤더에 담아 다시 요청한다. OAuth나 JWT를 사용하는 경우에도 이 헤더 필드를 통해 Bearer Token 등을 전송한다.
보안 강화를 위한 헤더는 다양한 공격을 방어하고 정보 보안을 개선하는 역할을 한다. Strict-Transport-Security(HSTS) 헤더는 브라우저가 해당 사이트에 향후 모든 접속을 HTTPS로 강제하도록 지시한다. Content-Security-Policy(CSP) 헤더는 크로스 사이트 스크립팅(XSS) 공격을 완화하기 위해 스크립트, 이미지 등 리소스의 로드 출처를 제한하는 정책을 정의한다.
쿠키 기반 세션 관리와 관련된 보안 헤더도 중요하다. Set-Cookie 헤더에 Secure, HttpOnly, SameSite 속성을 설정하면 쿠키의 안전성을 높일 수 있다. 또한 X-Frame-Options 헤더는 페이지가 <frame>, <iframe>, <embed>, <object> 내에서 렌더링되는 것을 방지하여 클릭재킹 공격을 차단한다.
헤더 필드 | 주요 목적 | 예시 값 또는 속성 |
|---|---|---|
| 서버에 자격 증명 전송 |
|
| 필요한 인증 방식 응답 |
|
| HTTPS 강제 |
|
| 리소스 로드 출처 제한 |
|
| 클릭재킹 방지 |
|
4.4. 연결 관리 헤더
4.4. 연결 관리 헤더
연결 관리 헤더는 HTTP 세션의 연결 상태와 지속성을 제어하는 데 사용된다. 특히 HTTP/1.1에서 도입된 지속 연결(Persistent Connection)의 효율적인 관리를 위해 중요한 역할을 한다. 주요 목적은 클라이언트와 서버 간의 TCP 연결을 재사용할지 여부를 협상하고, 연결을 정상적으로 종료하는 방법을 지정하는 것이다.
가장 대표적인 연결 관리 헤더는 Connection과 Keep-Alive이다. Connection 헤더는 현재 연결에 대한 제어 옵션을 지정한다. 값이 "close"이면 현재 요청-응답 트랜잭션 후 연결을 종료해야 함을 의미한다. 반면 "keep-alive"는 연결을 유지하겠다는 의사를 나타내지만, HTTP/1.1에서는 지속 연결이 기본값이므로 명시적 사용이 줄었다. 또한 이 헤더는 프록시를 통해 전달되지 말아야 할 헤더(예: Keep-Alive)를 지정하는 데에도 사용된다[5].
Keep-Alive 헤더는 지속 연결의 매개변수를 설정한다. 이 헤더는 연결이 유지될 최대 시간(timeout)과 해당 연결에서 허용될 최대 추가 요청 수(max)를 지정할 수 있다. 예를 들어, Keep-Alive: timeout=5, max=1000은 연결이 5초간 유휴 상태를 유지할 수 있고, 최대 1000개의 추가 요청을 처리할 수 있음을 의미한다. 이 헤더는 HTTP/1.0에서 지속 연결을 활성화하기 위해 필요했지만, HTTP/1.1부터는 기본 동작이므로 주로 매개변수 조정용으로 사용된다.
헤더 이름 | 설명 | 주요 값/매개변수 |
|---|---|---|
| 연결에 대한 제어 옵션을 지정. Hop-by-hop 헤더를 표시. |
|
| 지속 연결의 매개변수를 설정. |
|
| 클라이언트나 서버가 다른 프로토콜로 전환을 제안할 때 사용. |
|
Upgrade 헤더는 프로토콜 전환을 요청하는 데 사용된다. 예를 들어, HTTP/1.1 연결을 HTTP/2나 WebSocket으로 업그레이드할 때 이 헤더를 활용한다. 서버가 101 Switching Protocols 응답을 보내면 협상된 프로토콜로 전환이 이루어진다. Transfer-Encoding과 TE 헤더도 연결 관리와 관련이 깊다. Transfer-Encoding은 메시지 본문의 전송 인코딩 방식을 지정하며(예: chunked), TE 헤더는 클라이언트가 응답에서 받아들일 수 있는 전송 인코딩 확장을 서버에 알린다.
5. HTTP/1.1과 HTTP/2의 헤더 차이
5. HTTP/1.1과 HTTP/2의 헤더 차이
HTTP/1.1은 텍스트 기반의 프로토콜로, 헤더를 일반 텍스트 형식으로 전송한다. 각 HTTP 헤더 필드는 줄바꿈 문자(CRLF)로 구분되며, 요청이나 응답마다 헤더 블록이 반복적으로 전송된다. 이는 동일한 연결 내에서 여러 요청을 보내더라도 매번 중복된 헤더 필드(예: User-Agent, Host, Cookie)가 재전송되어 불필요한 오버헤드를 발생시킨다. 또한 헤더는 압축되지 않은 상태로 전송되어 대역폭을 낭비한다.
반면, HTTP/2는 이진 프레이밍 계층을 도입하여 헤더를 이진 형식으로 전송한다. 가장 큰 차이점은 헤더 압축을 위해 HPACK 알고리즘을 사용한다는 점이다. HPACK은 헤더 필드를 정적 테이블과 동적 테이블에 인덱싱하여 중복을 제거한다. 정적 테이블은 자주 사용되는 공통 헤더 필드(예: :method, :path, :status)를 미리 정의해 놓았으며, 동적 테이블은 연결 중에 교환된 헤더 필드를 추가하여 인코딩 효율을 높인다. 이를 통해 헤더 크기를 크게 줄일 수 있다.
프로토콜 설계상의 차이도 존재한다. HTTP/1.1에서는 헤더의 순서가 크게 중요하지 않았지만, HTTP/2에서는 HPACK의 압축 효율을 위해 특정 헤더 필드(예: :method, :scheme, :path)를 항상 먼저 보내는 것이 권장된다. 또한 HTTP/2는 요청과 응답에 대한 가상 스트림을 통해 멀티플렉싱을 지원하므로, 단일 연결에서 여러 요청의 헤더가 인터리빙되어 전송될 수 있다. 이는 HTTP/1.1의 헤드 오브 라인 블로킹 문제를 해결한다.
6. 헤더 압축
6. 헤더 압축
HTTP/1.1에서는 헤더가 평문으로 전송되며, 특히 쿠키와 같은 반복되는 헤더 필드로 인해 오버헤드가 발생할 수 있다. 이를 해결하기 위해 HTTP/2와 HTTP/3에서는 헤더를 압축하여 전송하는 메커니즘이 도입되었다. 헤더 압축은 중복된 정보를 제거하고 효율적인 인코딩을 통해 네트워크 트래픽을 줄이고 지연 시간을 단축하는 데 목적이 있다.
HTTP/2의 헤더 압축은 HPACK이라는 명시적인 압축 형식을 사용한다. HPACK은 헤더 필드를 정적 테이블과 동적 테이블로 관리하며, 허프만 코딩을 적용한다. 정적 테이블에는 자주 사용되는 헤더 필드(예: :method, :path, :status)와 값(예: GET, 200)이 미리 정의되어 있다. 동적 테이블은 연결 중에 교환된 헤더 필드로 업데이트된다. 송신측과 수신측은 동일한 테이블 상태를 유지하며, 헤더를 전송할 때는 테이블의 인덱스 참조, 값의 허프만 인코딩, 또는 리터럴 값 전송 방식을 조합하여 효율적으로 표현한다. 이 방식은 CRIME 공격과 같은 보안 취약점을 방지하도록 설계되었다.
HTTP/3에서는 QUIC 프로토콜 위에서 동작하는 QPACK을 사용한다. QPACK은 HPACK의 설계를 계승하지만, QUIC의 스트림이 독립적이고 순서가 보장되지 않을 수 있는 특성을 반영하여 수정되었다. HPACK에서는 헤더 블록의 순차적 디코딩이 필요했으나, QPACK은 스트림 간의 순서 의존성을 제거했다. 이를 위해 송신측이 테이블 업데이트를 확인했다는 신호를 별도의 제어 스트림을 통해 보내는 방식을 도입하여, 헤더 압축 해제의 지연을 방지하고 멀티플렉싱 성능을 향상시켰다.
프로토콜 | 압축 방식 | 주요 특징 |
|---|---|---|
압축 없음 | 헤더가 평문으로, 매 요청마다 반복 전송됨. | |
정적/동적 테이블과 허프만 코딩 사용. 순차적 디코딩. | ||
QUIC 환경 최적화. 순서 의존성 제거를 위한 별도 확인 메커니즘 사용. |
6.1. HPACK (HTTP/2)
6.1. HPACK (HTTP/2)
HPACK은 HTTP/2 프로토콜에서 HTTP 헤더를 효율적으로 압축하기 위해 설계된 이진 형식의 압축 방법이다. 이전 HTTP/1.x에서는 헤더가 반복적으로 전송되어도 텍스트 형식 그대로 전송되었지만, HPACK은 헤더 필드의 크기를 줄여 대역폭을 절약하고 지연 시간을 감소시킨다. HPACK의 설계 목표는 보안 취약점을 방지하는 것이었는데, 이는 CRIME과 같은 공격이 TLS 레벨의 압축을 악용하는 것을 차단하기 위함이었다[6].
HPACK의 동작 방식은 크게 정적 테이블, 동적 테이블, 허프만 코딩의 세 가지 요소로 구성된다. 정적 테이블은 자주 사용되는 61개의 공통 헤더 필드와 값(예: :method: GET, :scheme: https)을 미리 정의해 놓은 것이다. 동적 테이블은 통신 중에 새롭게 등장하는 헤더 필드와 값을 인덱싱하여 추가하며, 최근 사용된 순서로 관리되어 캐시처럼 동작한다. 허프만 코딩은 문자열 리터럴을 효율적으로 이진 인코딩하는 데 사용된다.
구성 요소 | 설명 | 예시 |
|---|---|---|
정적 테이블(Static Table) | 프로토콜 사양에 미리 정의된, 자주 사용되는 헤더 필드 목록 |
|
동적 테이블(Dynamic Table) | 통신 세션 중에 송신측과 수신측이 동적으로 업데이트하는 헤더 필드 목록 | 사용자 정의 헤더나 고유한 쿠키 값 등 |
허프만 코딩(Huffman Coding) | 헤더 필드 이름과 값의 문자열을 압축하는 엔트로피 코딩 방식 | 빈도가 높은 문자에 더 짧은 비트 코드를 할당 |
인코더는 헤더 목록을 처리할 때, 정적 테이블이나 동적 테이블에 완전히 일치하는 항목이 있으면 해당 인덱스만 전송한다. 값이 일부 다른 경우 '인덱스된 헤더 필드'로, 완전히 새로운 헤더는 '리터럴 헤더 필드'로 인코딩한다. 수신측 디코더는 동일한 테이블 상태를 유지하며 전송된 인덱스나 리터럴을 원래 헤더 목록으로 복원한다. 이 방식은 중복된 헤더의 전송을 극적으로 줄여, 특히 웹 페이지 로드 시 여러 동일한 헤더를 반복적으로 보내야 하는 상황에서 성능 향상 효과가 크다.
6.2. QPACK (HTTP/3)
6.2. QPACK (HTTP/3)
QPACK은 HTTP/3 프로토콜에서 HTTP 헤더를 압축하기 위해 설계된 효율적인 압축 형식이다. HTTP/2에서 사용되던 HPACK 압축 방식은 단일 TCP 연결을 전제로 하여 헤더 블록이 순서대로 도착한다고 가정한다. 그러나 HTTP/3의 기반이 되는 QUIC 프로토콜은 다중 스트림을 사용하고 패킷 손실 시 특정 스트림만 영향을 받기 때문에, 헤더 블록의 전송 순서가 보장되지 않는다. QPACK은 이러한 비순차적 전송 환경에서도 안정적으로 헤더 압축을 수행할 수 있도록 HPACK을 확장 및 수정한 것이다.
QPACK의 핵심 메커니즘은 동적 테이블 관리와 명시적 피드백을 통한 동기화에 있다. 인코더(일반적으로 서버)와 디코더(일반적으로 클라이언트)는 각각 독립적인 동적 테이블을 유지한다. 인코더는 헤더를 압축하여 스트림을 통해 보낼 때, 해당 헤더가 자신의 동적 테이블의 어떤 인덱스를 참조하는지 함께 알린다. 디코더는 패킷 손실로 인해 자신의 동적 테이블이 인코더의 테이블 상태와 달라질 수 있으므로, 특정 테이블 항목의 수신 및 처리 완료 여부를 별도의 제어 스트림을 통해 인코더에게 피드백한다. 이를 통해 인코더는 디코더가 안전하게 디코딩할 수 있는 테이블 인덱스 범위를 파악하고, 그에 맞춰 압축 방식을 조정한다.
이러한 설계는 복잡성을 증가시키지만, HTTP/3의 핵심 장점인 독립적인 스트림 처리와 멀티플렉싱을 해치지 않으면서 헤더 압축의 이점을 유지할 수 있게 한다. 결과적으로 QPACK은 HPACK과 유사한 높은 압축률을 제공하면서도, QUIC의 패킷 손실 회복성과 낮은 지연 시간 특성에 잘 부합한다. 표준은 필수 명령어 세트와 선택적 명령어 세트를 정의하여 구현의 유연성을 보장한다[7].
7. 보안 관련 헤더
7. 보안 관련 헤더
보안 관련 헤더는 웹 애플리케이션이 다양한 공격 벡터로부터 사용자와 서버를 보호하기 위해 사용되는 HTTP 헤더의 집합이다. 이 헤더들은 주로 브라우저에게 특정 보안 정책을 지시하거나, 민감한 정보가 노출되는 것을 방지하는 역할을 한다. 클릭재킹, 사이트 간 스크립팅(XSS), MIME 스니핑과 같은 일반적인 웹 공격을 완화하는 데 중점을 둔다.
가장 널리 사용되는 보안 헤더 중 하나는 콘텐츠 보안 정책(CSP)이다. CSP 헤더(Content-Security-Policy)는 브라우저가 로드할 수 있는 리소스(스크립트, 스타일시트, 이미지 등)의 출처를 제한함으로써 XSS 공격을 효과적으로 차단한다. 예를 들어, 인라인 스크립트의 실행을 금지하거나 신뢰할 수 있는 도메인에서만 스크립트를 로드하도록 정책을 설정할 수 있다. 또 다른 중요한 헤더는 HSTS(HTTP Strict Transport Security)로, Strict-Transport-Security 헤더를 통해 서버가 브라우저에게 향후 모든 통신을 반드시 HTTPS를 통해 암호화된 연결로만 수행하도록 강제한다. 이는 중간자 공격(MITM)이나 프로토콜 다운그레이드 공격을 방지한다.
기타 주요 보안 헤더는 다음과 같다.
헤더 이름 | 주요 목적 | 설명 |
|---|---|---|
| 클릭재킹 방지 | 페이지가 |
| MIME 스니핑 방지 | 브라우저가 파일의 MIME 타입을 추측( |
| 리퍼러 정보 제어 | 다른 페이지로 이동할 때 HTTP 리퍼러 헤더에 포함될 정보의 양을 제어하여 민감한 데이터 노출을 줄인다. |
| 브라우저 기능 제어 | 지오로케이션, 마이크, 카메라 등 특정 브라우저 API와 기능의 사용을 허용하거나 차단한다. |
이러한 헤더들은 방어적 프로그래밍의 일환으로, 서버 구성 파일(예: .htaccess, nginx.conf)이나 애플리케이션 코드 내에서 설정된다. 모든 헤더를 한꺼번에 적용하기보다는 애플리케이션의 실제 필요와 위험 평가에 따라 점진적으로 도입하는 것이 모범 사례이다.
7.1. CSP (콘텐츠 보안 정책)
7.1. CSP (콘텐츠 보안 정책)
CSP(Content Security Policy)는 XSS(Cross-Site Scripting), 데이터 주입 공격 등 특정 유형의 웹 기반 공격을 탐지하고 완화하기 위해 설계된 컴퓨터 보안 표준이다. 웹 개발자는 CSP를 사용하여 브라우저가 페이지에 대해 유효한 실행 가능한 스크립트의 출처를 제어할 수 있다. 이 정책은 Content-Security-Policy HTTP 헤더를 통해 서버에서 클라이언트로 전달된다.
CSP는 허용 목록 방식으로 작동한다. 정책은 하나 이상의 지시문(directive)으로 구성되며, 각 지시문은 특정 리소스 유형에 대해 허용된 출처를 정의한다. 주요 지시문으로는 default-src, script-src, style-src, img-src, connect-src, font-src, object-src, media-src, frame-src 등이 있다. 예를 들어, Content-Security-Policy: script-src 'self' https://trusted.cdn.com과 같은 헤더는 스크립트를 현재 페이지의 출처('self')와 https://trusted.cdn.com 도메인에서만 로드하도록 허용한다. 정책을 위반하는 리소스는 브라우저에 의해 차단된다.
정책은 보고(reporting)와 시행(enforcement)을 위해 별도 또는 함께 사용될 수 있다. Content-Security-Policy 헤더를 사용하면 정책이 시행되며 위반 사항이 발생하면 리소스가 차단된다. 반면, Content-Security-Policy-Report-Only 헤더를 사용하면 정책은 시행되지 않고 위반 사항만 지정된 report-uri 또는 report-to 지시문으로 정의된 엔드포인트에 보고된다[8]. CSP는 또한 'nonce-{값}'이나 'sha256-{해시값}'과 같은 인라인 스크립트나 스타일을 허용하기 위한 메커니즘을 제공하여 보안을 유지하면서도 필요한 인라인 코드의 실행을 가능하게 한다.
7.2. HSTS
7.2. HSTS
HSTS(HTTP Strict Transport Security)는 웹사이트가 HTTPS를 통해서만 접근되어야 함을 브라우저에 알리는 보안 메커니즘이다. 이 정책은 HTTP 응답 헤더인 Strict-Transport-Security를 통해 전달된다. HSTS가 활성화되면, 브라우저는 해당 사이트에 대한 모든 연결을 자동으로 암호화된 HTTPS로 업그레이드하며, 유효 기간 동안은 안전하지 않은 HTTP 연결을 시도하지 않는다.
HSTS 헤더의 주요 지시어(directive)는 다음과 같다.
지시어 | 설명 | 예시 |
|---|---|---|
| HSTS 정책이 적용될 시간(초 단위)을 지정한다. 필수 항목이다. |
|
| 이 지시어가 있으면, 모든 서브도메인에도 HSTS 정책이 적용된다. |
|
|
|
이 메커니즘은 중간자 공격(MITM)이나 프로토콜 다운그레이드 공격을 방지하는 데 핵심적인 역할을 한다. 사용자가 http://example.com을 입력하거나 안전하지 않은 링크를 클릭하더라도, 브라우저는 내부적으로 https://example.com으로 요청을 변경한다. 또한, 브라우저는 유효한 인증서 검증을 우회하는 사용자 경고를 표시하지 않도록 한다[10].
HSTS를 구현하려면 웹 서버(예: Apache, Nginx)의 설정 파일에 Strict-Transport-Security 헤더를 추가해야 한다. 사이트를 브라우저의 HSTS 사전 로드 목록에 제출하려면, 공식 HSTS Preload List 사이트를 통해 등록 절차를 완료해야 하며, 이는 모든 주요 브라우저에 정책이 영구적으로 적용되는 효과를 가져온다.
8. 사용자 정의 헤더
8. 사용자 정의 헤더
HTTP 표준에 정의된 헤더 외에도, 클라이언트와 서버는 필요에 따라 자유롭게 사용자 정의 헤더를 정의하고 사용할 수 있다. 이러한 헤더는 주로 애플리케이션별 특수한 정보를 전달하거나, 특정 미들웨어나 프록시 서버 간의 통신에 활용된다. 관례적으로, 사용자 정의 헤더의 필드 이름 앞에는 'X-' 접두사를 붙여 표준 헤더와 구분하는 것이 일반적이었다[11]. 그러나 최근 RFC 6648에서는 이 관례를 공식적으로 폐기하고, 불필요한 접두사 사용을 권장하지 않는다.
사용자 정의 헤더는 다양한 목적으로 활용된다. 예를 들어, 서버 프레임워크 정보를 알리는 X-Powered-By, 요청을 추적하기 위한 고유 식별자를 담는 X-Correlation-ID 또는 X-Request-ID, 클라이언트의 특정 기능 지원 여부를 표시하는 X-Requested-With 등이 널리 사용된다. 또한, CDN이나 리버스 프록시는 종종 X-Forwarded-For, X-Forwarded-Host, X-Forwarded-Proto와 같은 헤더를 통해 원본 요청 정보를 백엔드 서버에 전달한다.
사용자 정의 헤더를 설계할 때는 몇 가지 주의사항이 있다. 첫째, 이미 표준으로 정의된 헤더 이름과의 충돌을 피해야 한다. 둘째, 헤더 이름은 대소문자를 구분하지 않지만, 관례적으로 단어의 첫 글자를 대문자로 하는 파스칼 케이스(Pascal Case)를 사용한다[12]. 셋째, 의미가 명확하고 필요한 경우에만 사용해야 하며, 과도하게 많은 사용자 정의 헤더는 네트워크 오버헤드를 증가시킬 수 있다. 마지막으로, 보안상 민감한 정보는 절대 평문으로 헤더에 포함해서는 안 된다.
9. 헤더 최적화와 모범 사례
9. 헤더 최적화와 모범 사례
불필요한 HTTP 헤더를 제거하는 것은 네트워크 오버헤드를 줄이는 기본적인 최적화 방법이다. 사용하지 않는 X-Powered-By와 같은 프레임워크 식별 헤더나 디버깅 목적의 헤더는 프로덕션 환경에서 제거하는 것이 좋다. 또한, 중복된 헤더 필드가 전송되지 않도록 주의해야 한다.
캐싱 관련 헤더를 적절히 설정하면 서버 부하를 줄이고 사용자 경험을 개선할 수 있다. 정적 자원(이미지, CSS, JavaScript 파일 등)에는 Cache-Control 헤더를 사용해 max-age를 길게 설정하고, immutable 지시어를 추가하여 재검증 요청을 방지할 수 있다. 반면, 개인화된 콘텐츠나 자주 변경되는 데이터에는 no-cache나 no-store를 사용하여 캐싱을 제한해야 한다.
최적화 대상 | 권장 모범 사례 | 기대 효과 |
|---|---|---|
헤더 크기 | 불필요/중복 헤더 제거, 값 압축[13] | 네트워크 트래픽 감소 |
캐싱 정책 | 정적 자원은 장기 캐싱, 동적 콘텐츠는 적절한 검증 설정 | 서버 요청 수 감소, 로딩 속도 향상 |
보안 | Content-Security-Policy, Strict-Transport-Security 등 필수 보안 헤더 적용 | 웹 애플리케이션 보안성 강화 |
연결 효율 | 연결 설정 오버헤드 감소 |
보안 헤더의 누락은 일반적인 취약점이다. 콘텐츠 보안 정책(CSP)을 설정하여 XSS(교차 사이트 스크립팅) 공격을 완화하고, HSTS(HTTP Strict Transport Security) 헤더를 통해 HTTPS 강제 사용을 보장해야 한다. 또한, 민감한 정보가 포함될 수 있는 Server나 X-AspNet-Version 같은 헤더는 노출을 최소화하는 것이 안전하다.
최신 HTTP/2나 HTTP/3 프로토콜을 사용하면 헤더 압축(HPACK, QPACK)이 기본 적용되어 헤더 오버헤드가 크게 줄어든다. 그러나 프로토콜 업그레이드와 관계없이, 애플리케이션 수준에서 헤더 필드의 수와 크기를 의식적으로 관리하는 것이 전체 성능에 기여한다.
