RFC 7230 스리슬쩍 햝아먹기

정하나둘·2023년 7월 31일
0

webserv

목록 보기
2/4

HTTP 1.1에 관한 최신 문서는 RFC 9112이나 21년 개정되어 번역본도 없고 그거 일일이 번역하고 이해하다가 헛구역질이 올라올 것 같아 누군가 열심히 노력해서 번역본을 만들어놓으신 RFC 7230~7235를 읽고 요약해보기로 했다.

RFC 7230부터 7235까지가 HTTP 1.1 관련 문서다.

7230: http 1.1메세지 구문과 라우팅 기본 규칙, 메세지 구조, 요청과 응답, 메시지 포맷, 헤더 필드

7231: http 1.1 의미론과 컨텐츠에 관련된 내용, 각각의 메소드에 의미 설명(get, post, put, delete)

7232: 조건부 요청을 위한 메커니즘(클라이언트가 서버에게 자원 다운로드 전 해당 자원 미수정 확인)

7233: 부분적인 자원 요청 지원을 위한 범위 요청 메커니즘(자원의 일부분만 요청할 수 있게 해줌. 파일 다운로드와 스트리밍에 유용)

7234: 캐싱 메커니즘, 웹 캐시 동작과 헤더 필드 설명.

7235: 인증과 보안을 위한 메커니즘 설명, 서버에 대한 접근 제어를 위한 기본적인 인증 방법들과 보안 헤더에 관한 내용을 다룸.

1. 주요 표기법

연산자를 사용하여 쉼표로 구분된 리스트를 콤팩트하게 정의 가능한 목록 확장자가 있는 [RFC5234]-ABNF- 표기법을 사용한다.

ALPHA (letters)

CR (carriage return)

CRLF (CR LF)

CTL (controls)

DIGIT (decimal 0-9)

DQUOTE (double quote)

HEXDIG (hexadecimal 0-9/A-F/a-f)

HTAB (horizontal tab)

LF (line feed)

OCTET (any 8-bit sequence of data)

SP (space)

VCHAR (any visible [USASCII] character)

2. Architecture

클라이언트는 HTTP 요청을 서버에 요청 메세지 형식, method, URI와 프로토콜 버전을 포함한 Request-line을 시작으로 헤더 필드, 요청 수정자, 클라이언트 정보, 표현 메타데이터, 헤더 부분의 끝을 나타내는 빈줄을 포함하여, 마지막으로 페이로드 본문을 포함하는 메세지 본문을 보낸다.

서버는 클라이언트의 요청에 하나 또는 다수의 HTTP 응답 메시지를 각각의 프로토콜 버전, 성공 또는 에러 코드, 원문으로된 상태 코드를 포함한 status-line을 시작으로, 가능하다면 서버 정보, 리소스 메타데이터와 표현 메타데이터를 포함하는 헤더 필드 다음에 헤더 부분의 끝을 나타내는 빈 줄을 포함하여, 마지막으로 페이로드 body를 포함한 메시지 본문(만약에 있다면)을 통해 응답한다.

  • 요청 메세지 : 클라이언트가 서버에서 요청하는 메세지
    형식:

    - 메서드 : 어떻게 처리를 해야 하는지를 담고 있음
    - GET : 존재하는 자원에 대한 요청
    - POST : 새로운 자원을 생성
    - PUT : 존재하는 자원에 대한 변경
    - DELETE : 존재라는 자원에 대한 삭제
    get, post, put, delete는 메서드이다.
    - 경로 : 가져오려는 리소스의 경로를 표시
    - 프로토콜 버전 : HTTP 프로토콜의 버전을 표시
    - 헤더 : 서버에 대한 추가 정보를 전달. 호스트의 정보나 접속하고 있는 사용자의 정보, 그리고 열려고 하는 페이지의 정보 등을 확인할 수 있습니다.
    - user-agent : 웹 브라우저의 다른 표현. 요청하는 웹 브라우저의 정보 및 운영체제를 표시
    - accep-encoding : 클라이언트가 이해할 수 있는 압축 방식을 표시. 이를 표시해서 서버에 전송하면 서버는 필요한 경우 리소스를 압축하여 반환
    - 공백 라인 : 헤더와 본문 구분하는 역할
    - 본문 : POST처럼 서버에 새로운 자원을 추가하는 경우에 들어가는 선택적인 요소

다음 예시는 URI에서 GET 요청을 위한 일반적인 메세지 교환을 보여준다.

/****************************/
/*           URI            */ 
/****************************/
	http://www.example.com/hello.txt


/****************************/
/*      CLIENT REQUEST      */ 
/****************************/

     GET /hello.txt HTTP/1.1
     User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3
     Host: www.example.com
     Accept-Language: en, mi


/****************************/
/*      SERVER RESPONSE     */ 
/****************************/

     HTTP/1.1 200 OK
     Date: Mon, 27 Jul 2009 12:28:53 GMT
     Server: Apache
     Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
     ETag: "34aa387-d-1568eb00"
     Accept-Ranges: bytes
     Content-Length: 51
     Vary: Accept-Encoding
     Content-Type: text/plain

     Hello World! My payload includes a trailing CRLF.

중개자(Intermediary)의 3가지 형태는 다음과 같다.

Proxy = 웹 서버에서 가져온 데이터를 클라이언트에 전송 후 캐시로 저장(같은 데이터를 요청하면 서버까지 가지않고 캐시에서 바로 데이터 전송)
Gateway(reverse proxy) = HTTP 이외의 네트워크(사설망)과의 통로역할
Tunnel(TLS) = 안전한 통신을 위해 사용

Cache: 캐시는 이전 응답 메세지의 로컬 보관소로 메시지의 저장, 검색, 삭제를 관리하는 서브 시스템이다. 캐시는 캐시 가능한 응답을 저장하여 향후 동일한 요청에 대한 응답 시간과 네트워크 대역폭 사용을 줄인다.
하지만 캐시는 서버가 터널(TLS)역할을 하는 동안에는 사용할 수 없다.

캐시의 효과는 체인의 참여자 중 하나가 해당 요청에 적용할 수 있는 캐시된 응답을 가지고 있는 경우 요청/응답 체인이 단축되는 것이다. 다음은 B가 UA 또는 A에 의해 캐시되지 않은 요청에 대한 O(경유 C)의 이전 응답의 캐시된 사본을 가지고 있는 경우의 결과 체인을 보여준다.

  >        >
UA ====  A ==== B - - - - C - - - -  O
    <        <

3. Message Format

HTTP 메시지 형식에 대해 설명하는 부분이다.
HTTP 메시지는 start-line을 시작으로, 여러 헤더필드, 헤더 부문의 끝을 나타내는 빈 줄 및 선택적 메시지 본문으로 구성된다.

HTTP-message   = start-line
                 *( header-field CRLF )
                 CRLF
                 [ message-body ]

분석하는 일반적인 절차는 start-line을 읽고, 각 헤더 필드를 빈 행까지 필드 이름으로 해시 테이블로 읽은 다음 분석된 데이터를 사용하여 메시지 본문이 필요한지 여부를 확인한다. 메시지 본문이 표시된 경우, 메시지 본문 길이와 동일한 octet의 양을 읽거나 커넥션을 닫을 때까지 스트림으로 읽는다.
(octet: 네트워크 관련 분야에서는 서로 연결되는 두 대의 장비가 1byte=8bit라는 것을 보장할 수 없으므로 octet이라는 표현을 사용해 1바이트는 8bit로 정확하게 명시하는 것, byte와 같다고 생각하면 편하다.)

발신자는 start-line과 첫 번째 헤더 필드 사이에 공백을 보내선 안되고, start-line과 첫 번째 헤더 필드 사이에 공백을 수신하는 수신자는 메시지를 유효하지 않은 것으로 거부하거나 메시지를 더 이상 처리하지 않고 각 공백이 지정된 줄을 소비해야 한다.

HTTP 메시지는 클라이언트->서버(요청), 서버->클라이언트(응답)두 종류가 있으므로 두 유형의 메세지(요청, 응답)는 start-line(요청, 응답)과 메세지 본문의 길이를 결정하기 위한 알고리즘에서만 다르다.

이론적으로 클라이언트도 요청을 수신할 수 있고 서버도 응답을 수신할 수 있지만 서버는 요청만 예상(수신)하도록 구현되고 클라이언트는 응답만 예상(수신)하도록 구현된다.

start-line     = request-line / status-line

Request line

method 토큰을 시작으로, 공백(SP), request-target, 공백(SP), 프로토콜 버전, 그리고 CRLF를 끝으로 한다.

request-line   = method SP request-target SP HTTP-version CRLF

method

method 토큰은 대상 리소스를 실행하기 위한 요청 메서드를 표시한다. 요청 메서드는 대 소문자를 구별한다.

method = token

request target

request target은 요청을 적용할 대상 리소스를 식별한다.

세 구성요소(method, request-target, HTTP-version CRLF)는 공백이 허용되지 않기 때문에 수신자는 공백을 분할하여 request-line을 구성 요소 부분으로 분할한다.

유효하지 않은 request-line의 수신자는 400(Bad Request)오류 또는 301(Moved Permanently)리다이렉트로 응답해야 하며 리다이렉트없이 request데이터를 수정해서 처리하면 안된다.

만약 서버가 처리 할 수 있는 시작줄의 길이를 초과하면 501에러 처리해야한다. 모든 HTTP 발신자와 수신자는 최소 octets 8000길이의 request-line을 지원하는 것을 권장한다.

Status Line

응답 메세지의 첫 번째 줄은 status-line이며,
프로토콜 버전, 공백(SP), status-code, 공백(SP), status-code를 설명하는 빈 텍스트 구분, CRLF 로 구성된다.

status-line = HTTP-version SP status-code SP reason-phrase CRLF

status-code

status-code 요소는 서버가 클라이언트의 해당 요청을 이해하고 충족하려고 시도한 결과를 설명하는 세 자리의 정수 코드이다. 응답 메시지의 나머지 부분은 해당 상태 코드에 대해 정의된 의미론을 고려하여 해석된다.

status-code    = 3DIGIT

reason-phrase

reason-phrase요소는 숫자 상태 코드와 관련된 텍스트 설명을 제공하는 목적으로 존재한다. 클라이언트는 reason-pharse 내용을 무시해야 한다.

reason-phrase  = *( HTAB / SP / VCHAR / obs-text )

Header Fields

각 헤더 필드는 대소문자를 구분하지 않는 필드 이름 뒤에 콜론(":"), 선택적 앞의 공백(OWS), 필드 값,선택적 뒤의 공백(OWS)으로 구성된다.

header-field   = field-name ":" OWS field-value OWS

field-name     = token
field-value    = *( field-content / obs-fold )
field-content  = field-vchar [ 1*( SP / HTAB ) field-vchar ]
field-vchar    = VCHAR / obs-text
 
obs-fold       = CRLF 1*( SP / HTAB )
                    ; obsolete line folding
                    ;

field-name 토큰은 해당 field-value를 헤더 필드에서 정의한 의미론을 갖는 것으로, 레이블을 지정한다. 예를 들어 Date 헤더 필드는 메시지의 시작 타임 스탬프를 포함하는 필드로 정의된다.

Whitespace

OWS(선택적 공백), RWD(필수 공백), BWS(불량 공백) 세가지 규칙 사용.

  • OWS 규칙은 0 이상의 선형 공백 octets이 나타나는 곳에 사용된다. 가독성을 향상시키기 위해 선택적 공백(OWS)을 선호하는 프로토콜 요소의 경우, 발신자는 단일 SP로서 선택적 공백(OWS)을 생성해야 한다. 그렇지 않은경우, 발신자는 내부 메시지 필터링 중에 유효하지 않거나 원하지 않는 프로토콜 요소를 화이트아웃하는 데 필요한 경우를 제외하고 선택적 공백을 생성해서는 안 된다.
  • RWS 규칙은 필드 토큰을 분리하기 위해 하나 이상의 선형 공백 octets이 필요한 경우에 사용된다. 발신자는 단일 SP로서 RWS를 생성해야 한다.
  • BWS 규칙은 오직 역사적인 이유로 선택적 공백(OWS)을 허락하는 문법에서 사용된다. 발신자는 메시지에서 BWS를 생성해서는 안된다. 수신자는 이러한 잘못된 공백을 구문 분석한 후 프로토콜 요소를 해석하기 전에 제거해야 한다.
OWS            = *( SP / HTAB )		//공백이 0개 이상
                    ; optional whitespace
RWS            = 1*( SP / HTAB )	//공백이 1개 이상
                    ; required whitespace
BWS            = OWS		//공백이 0개 이상
                    ; "bad" whitespace

Message body

메세지에서 본문이 허용되는 시기에 대한 규칙은 요청과 응답에 따라 다르다.
요청에서 메세지 본문이 있으면 Content-length 또는 Transfer-Encoding 헤더 필드로 표시된다.
응답에서 메세지 본문의 존재 여부는 응답하는 요청 메서드와 응답 상태 코드(status-code)에 따라 달라진다.
Head 요청 메서드에 대한 응답은 헤더 필드가 있는 경우 요청 메서드가 GET 되었을 때의 값만 나타내므로 메세지 본문을 포함하지 않는다.
CONNECT 요청 메서드에 2xx (Successful) 응답은 메시지 본문 대신 터널 모드로 전환한다. 모든 1xx (informational), 204 (No Content) 및 304 (Not Modified) 응답에는 메시지 본문이 포함되지 않는다. 다른 모든 응답에는 메시지 본문이 포함되지만, 본문의 길이는 0일 수 있다.

Transfer-Encoding

Transfer-Encoding 헤더 필드에는 메시지 본문을 형성하기 위해 페이 로드 본문에 적용된(또는 적용될) 전송 코딩 순서에 해당하는 전송 코딩 이름을 나열한다. 전송 코딩은 아래 #4에서 다룬다.

Transfer-Encoding = 1#transfer-coding

Content-Length

메시지에 Transfer-Encoding 헤더 필드가 없는 경우, Content-Length 헤더 필드는 잠재적 페이 로드(순수 데이터)본문에 대해 예상되는 크기를 10진수로 제공할 수 있다. 페이 로드 본문을 포함하는 메시지의 경우, Content-Length 필드 값은 본문(및 메시지)이 끝나는 위치를 결정하는 데 필요한 프레임 정보를 제공한다. 페이 로드 본문이 포함되지 않은 메시지의 경우, Content-Length는 선택된 표현의 크기를 나타낸다.

Content-Length = 1*DIGIT

Message body Length

메시지 본문의 길이는 다음 중 하나에 의해 결정된다(우선 순위 순서대로)

  1. HEAD 요청에 대한 응답과 1xx(Informational), 204(No Content) 또는 304(Not Modified) 상태 코드 응답은 메시지에 있는 헤더 필드에 관계 없이 헤더 필드 다음의 첫 번째 빈 줄로 항상 종료되므로 메시지 본문을 포함할 수 없다.

  2. CONNECT 요청에 대한 2xx(Successful) 응답은 헤더 필드를 마치는 빈 줄 직후 커넥션은 터널이 됨을 내포한다. 클라이언트는 이러한 메시지에 수신된 Content-Length 또는 Transfer-Encoding 헤더 필드를 반드시 무시해야 한다.

  3. Transfer-Encoding 헤더 필드가 있고 청크 전송 코딩(Section 4.1)이 최종 인코딩인 경우, 전송 코딩이 데이터가 완료되었음을 나타낼 때까지 청크 데이터를 읽고 디코딩 하여 메시지 본문 길이를 결정한다.
    응답에 Transfer-Encoding 헤더 필드가 있고 청크 분할 전송 코딩이 최종 인코딩이 아닌 경우, 서버가 커넥션을 닫을 때까지 커넥션을 읽어 메시지 본문 길이를 결정한다. 요청에 Transfer-Encoding 헤더 필드가 있고 청크 전송 코딩이 최종 인코딩이 아닌 경우 메시지 본문 길이를 신뢰할 수 없다; 서버는 400(Bad Request) 상태 코드로 응답한 다음, 커넥션을 반드시 닫아야 한다.
    메시지가 Transfer-Encoding 및 Content-Length 헤더 필드와 함께 수신되면 Transfer-Encoding이 Content-Length를 재정의한다. 그러한 메시지는 요청 smuggling(Section 9.5) 또는 응답 분할(Section 9.4)을 수행하려는 시도를 나타낼 수 있으며 오류로 취급되어야 한다. 발신자는 이러한 메시지를 다운 스트림으로 전달하기 전에 수신된 Content-Length 필드를 반드시 제거해야 한다.

  4. Transfer-Encoding이 없는 메시지를 수신하거나 여러 Content-Length 헤더 필드들의 field-value가 다르거나 단일 Content-length 헤더 필드가 잘못된 경우, 메시지 프레임은 유효하지 않으며 수신자는 이를 복구할 수 없는 오류로 간주 해야 한다. 요청 메시지인 경우, 서버는 400 (Bad Request) 상태 코드로 응답한 다음 커넥션을 닫아야 한다. 프락시에서 수신한 응답 메시지인 경우, 프락시는 서버에 대한 커넥션을 닫고 수신된 응답을 무시하고, 502 (Bad Gateway)을 클라이언트에게 전송해야 한다. 사용자 에이전트가 수신한 응답 메시지인 경우, 사용자 에이전트는 서버에 대한 커넥션을 닫고 수신된 응답을 삭제해야 한다.

  5. Transfer-Encoding이 없는 유효한 Content-Length 헤더 필드가 있는 경우, 10진수 값은 octet으로 예상되는 메시지 본문 길이를 정의한다. 발신자가 커넥션을 닫거나 표시된 octet 수를 수신하기 전에 시간이 초과되면, 수신자는 메시지가 불완전한 것으로 간주하고 커넥션을 반드시 닫아야 한다.

  6. 이 메시지가 요청 메시지이고 위의 메시지 중 하나가 참이 아니면 메시지 본문 길이가 0이다.(메시지 본문이 없음).

  7. 그렇지 않으면, 이것은 선언된 메시지 본문 길이가 없는 응답 메시지이므로, 메시지 본문 길이는 서버가 커넥션을 닫기 전에 수신한 octet 수로 결정된다.

4. Transfer Codings

전송 코딩이란 안전한 전송을 보장하기 위해 리소스(데이터)에 적용돼야 하는 인코딩 변환 방식을 나타낸다.

헤더에 삽입되는 문법은 다음과 같다.

/*********************/
/*      REQUEST      */ 
/*********************/
TE: compress
TE: deflate
TE: gzip
TE: trailers

TE: trailers, deflate;q=0.5 // 여러 방식을 함께 기술할 때는 콤마 사용

/**********************/
/*      RESPONSE      */ 
/**********************/
Transfer-Encoding: chunked
Transfer-Encoding: compress
Transfer-Encoding: deflate
Transfer-Encoding: gzip

Transfer-Encoding: gzip, chunked // 여러 방식을 함께 기술할 때는 콤마 사용
청크 전송 코딩은 페이 로드 본체의 각각 자체 크기를 표시하여 전송하며, OPTIONAL 트레일러를 포함하는 헤더 필드 뒤에, 일련의 청크를 순차적으로 전송하기 위해 페이 로드 본체를 감싼다. 청크를 사용하면 알 수 없는 크기의 콘텐츠 스트림을 길이가 제한된 버퍼의 순서로 전송할 수 있으며, 이를 통해 송신자는 커넥션 영속성을 유지하고 수신자는 전체 메시지를 수신한 시점을 알 수 있다.
 
 
 
chunked-body   = *chunk
                  last-chunk
                  trailer-part
                  CRLF
 
chunk           = chunk-size [ chunk-ext ] CRLF
                        chunk-data CRLF
chunk-size    = 1*HEXDIG
last-chunk    = 1*("0") [ chunk-ext ] CRLF
 
chunk-data     = 1*OCTET ; a sequence of chunk-size octets

Chunked

콘텐츠의 사이즈가 큰 경우나 얼마인지 모를 때 사용되는 인코딩 방식으로 콘텐츠 크기 계산에도 시간이 걸리고 전송에도 시간이 걸리므로, 일정 크기로 잘라 전송하는 방식이다. 따라서 content-length는 헤더에서 생략된다.
서버는 크기가 0인 chunk로 콘텐츠의 끝임을 알려주고 다음 응답을 기다리거나 종료한다.

HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked

this is jinhyeok...\r\n
hello world~~~~~~~\r\n
hahaha\r\n
0\r\n
\r\n

compress

Lempel-Ziv-Welch (LZW) 알고리즘(압축 방식의 한 종류)을 사용한 인코딩.

deflate

Lempel-Ziv (LZ77) 압축 알고리즘과 허프만 코딩을 결합하여 사용하는 zlib 데이터 포맷 방식의 인코딩.

gzip

Lempel-Ziv (LZ77) 32비트 Cyclic Redundancy Check(CRC) 방식의 인코딩.

5. Message Routing

HTTP 요청시 주소창에 URL을 적게 되는데 이 때의 라우팅에 대해 기술하고 있다.

Inbound(클라이언트에서 서버쪽으로) 커넥션인 경우

  • 유효한 URL(URI)인지 검사
  • 캐시에 먼저 요청
  • 캐시에서 해당 응답을 못 찾으면 프록시 사용
  • 프록시로도 충족되지 않으면 대상 리소스에 직접 요청

인바운드 커넥션이 형성된 뒤에 클라이언트는 URL을 4가지 방식의 포맷으로 만들어 요청 메시지를 보내게 된다.
request target =

  • origin-form
  • absolute-form
  • authority-form
  • asterisk-form

origin-form

대부분의 request-target의 공통 양식은 original-form이다.

origin-form    = absolute-path [ "?" query ]

예를 들어, 클라이언트는 http://www.example.org/where?q=now 같은 식별된 리소스의 표시로 검색할 것이다.

원서버로부터 직접 포트 80에 대한 TCP 커넥션을 열고(또는 재사용하고) 호스트 "www.example.org"과 다음줄을 보냈을 것이다.

GET /where?q=now HTTP/1.1
Host: www.example.org

요청 메시지의 나머지 부분이 뒤따른다.

absolute-form

GET과 함께 주로 사용되며 프록시에 연결됐을 때 사용한다.

GET http://www.example.org/pub/WWW/TheProject.html HTTP/1.1

Authority-form

하나 또는 그 이상의 프락시들을 통해 터널을 설립하기 위해 CONNECT 요청을 할 때 사용된다.(CONNECT만 사용 가능)

CONNECT www.example.com:80 HTTP/1.1

Asterisk-form

서버 전체 OPTIONS 요청에서만 사용된다.
asterisk-form = "*"
즉, OPTIONS 요청에서만 사용되며, 서버 자체를 나타낼 때 사용된다.

OPTIONS * HTTP/1.1

예를 들어
OPTIONS http://www.example.org:8001 HTTP/1.1 요청은
host “www.example.org"의 8001 포트에 연결된 후
마지막 프락시에 의해
OPTIONS * HTTP/1.1
Host: www.example.org:8001이 전송됐을 것이다.

6. Connection Management

서버와 클라이언트의 연결을 어떤 방식으로 관리할지를 기술하는 부분이다.
Connection 헤더 필드는 커넥션이 완료된 뒤 연결을 유지할지, 끊을지를 정하게 된다.

“Connection” 헤더 필드를 통해 발신자는 현재 커넥션에 대해 원하는 제어 옵션을 표시할 수 있다. 메시지를 전달하기 전에 프락시 또는 게이트웨이가 수신된 커넥션 옵션을 반드시 제거하거나 바꾸어야 한다.

Connection: keep-alive
Connection: close

단 keep-alive는 HTTP/1.1에서 default이다.

Connection 헤더 필드는 hop-by-hop만을 위한 헤더 필드를 end-to-end와 구분짓는다.

hop-by-hop : 데이터가 중간 노드들에게도 데이터를 전달하고 확인하며 이동되는 방식.
end-to-end : 중간 매개는 상관하지 않고 데이터를 전달하는 방식.

7은 앞에서 사용했던 헤더 필드 값 정의를 가독성 좋게 나타내기 위한 ABNF를 알려주는 것이라 생각해 생략했다.

8. IANA Considerations

헤더 필드 목록, URI scheme 등에 관한 내용이다.

   /* Header Field */
   +-------------------+----------+----------+---------------+
   | Header Field Name | Protocol | Status   | Reference     |
   +-------------------+----------+----------+---------------+
   | Connection        | http     | standard | Section 6.1   |
   | Content-Length    | http     | standard | Section 3.3.2 |
   | Host              | http     | standard | Section 5.4   |
   | TE                | http     | standard | Section 4.3   |
   | Trailer           | http     | standard | Section 4.4   |
   | Transfer-Encoding | http     | standard | Section 3.3.1 |
   | Upgrade           | http     | standard | Section 6.7   |
   | Via               | http     | standard | Section 5.7.1 |
   +-------------------+----------+----------+---------------+
   | Close             | http     | reserved | Section 8.1   |
   +-------------------+----------+----------+---------------+
   
   /* URI Scheme */ 
   +------------+------------------------------------+---------------+
   | URI Scheme | Description                        | Reference     |
   +------------+------------------------------------+---------------+
   | http       | Hypertext Transfer Protocol        | Section 2.7.1 |
   | https      | Hypertext Transfer Protocol Secure | Section 2.7.2 |
   +------------+------------------------------------+---------------+
   
   /* HTTP Transfer Coding */
   +------------+--------------------------------------+---------------+
   | Name       | Description                          | Reference     |
   +------------+--------------------------------------+---------------+
   | chunked    | Transfer in a series of chunks       | Section 4.1   |
   | compress   | UNIX "compress" data format [Welch]  | Section 4.2.1 |
   | deflate    | "deflate" compressed data            | Section 4.2.2 |
   |            | ([RFC1951]) inside the "zlib" data   |               |
   |            | format ([RFC1950])                   |               |
   | gzip       | GZIP file format [RFC1952]           | Section 4.2.3 |
   | x-compress | Deprecated (alias for compress)      | Section 4.2.1 |
   | x-gzip     | Deprecated (alias for gzip)          | Section 4.2.3 |
   +------------+--------------------------------------+---------------+
   
   /* Content Coding */
   +------------+--------------------------------------+---------------+
   | Name       | Description                          | Reference     |
   +------------+--------------------------------------+---------------+
   | compress   | UNIX "compress" data format [Welch]  | Section 4.2.1 |
   | deflate    | "deflate" compressed data            | Section 4.2.2 |
   |            | ([RFC1951]) inside the "zlib" data   |               |
   |            | format ([RFC1950])                   |               |
   | gzip       | GZIP file format [RFC1952]           | Section 4.2.3 |
   | x-compress | Deprecated (alias for compress)      | Section 4.2.1 |
   | x-gzip     | Deprecated (alias for gzip)          | Section 4.2.3 |
   +------------+--------------------------------------+---------------+

9. Security Considerations

응답 분할: 요청에 있는 파라미터가 응답헤더로 다시 전달되는 경우, 파라미터 내 개행문자 CR 혹은 LF가 존재하면 HTTP응답이 분리될 수 있다. HTTP 응답 분할 공격은 이러한 취약점을 통해 응답 메시지에 악의적인 코드를 주입함으로써 캐시를 훼손하는 취약점이다.

예시는 해당 블로그에서 해결할 수 있다.
https://m.blog.naver.com/skinfosec2000/220694143144

요약

start-line(시작줄)부분

method 토큰을 시작으로, 공백 (SP), request-target, 공백 (SP), 프로토콜 버전, 그리고 CRLF를 끝으로 한다.

시작줄 정보가 유효하지 않으면 400또는 301(리다이렉트)상태코드로 응답한다.

또한 서버는 리다이렉트없이 request데이터를 수정해서 처리하면 안된다.

만약 서버가 처리 할 수 있는 시작줄의 길이를 초과하면 501에러 처리해야한다.

헤더부분

start-line(시작줄)이후 헤더필드가 CRLF기준으로 나누어져있다. 만약 시작줄과 헤더 블록이 분리(공백삽입 또는 CRLF두번 이상 삽입)되어 있다면 클라이언트의 request를 무시해야 된다.

클라이언트는 Host헤더를 무조건 보내야하며, 시작줄바로 다음에 위치 할 것을 권장한다. 헤더와 콜론사이에 공백이 있어서는 안된다. 헤더의순서는 큰 영향이 없다. 쿠키헤더만 예외적으로 파싱해야 하는 부분이 있다.

body부분

conf파일에서 지정한 client_max_bodysize를 초과하는 request가 들어오면 413에러페이지를 응답한다.

클라이언트의 행동

클라이언트는 서버에 연결시도시 절대 자동재시도를 하면 안된다.

서버의 행동

응답을 보내고 바로 소켓을 close하면 안된다. 클라이언트는 응답을 수신하지 못하는 상황이 발생 할 수 있다. 일반적으로 서버는 클라이언트와의 읽기/쓰기 연결에서 쓰기만 닫고, 클라이언트에서 close를 송신하면 서버에서 끝까지 패킷을 읽다가 완전히 종료한다. 서비스거부공격이나 응답분할공격이 의심되면 요청을 차단 할 수도있다.

http의 오해

웹브라우저와 서버간의 통신만을 위한 프로토콜이 아니다. 사물통신(IOT)와의 통신에도 사용 될 수 있으므로 웹브라우저에 국한되서 작동한다고 생각하는 것은 잘못된 것이다.

응답분할 공격 예방법

인코딩된 CR 및 LF (%0D %0A)데이터에 대한 요청을 필터링(헤더가 두 개 이상으로 나뉘어지는 것을 방지).

http 로그데이터 취급

본질적으로 기밀이며, 취급은 각 국가의 법고하 규정에 의해 제한될 수 있다. http에서는 재식별을 막는 방법이 역부족하므로 클라이언트에서 로그데이터에 접속하는 키가 가명일지라도 안전하지 않다.

참고 블로그
https://velog.io/@augus-xury/RFC

profile
내가 다시 보려고 만드는 42서울 본과정 블로그

0개의 댓글