[WEB 개발 기초] HTTP의 특징을 파헤치자 ② : HTTP 메시지

이민선(Jasmine)·2023년 5월 20일
0

WEB 개발 기초

목록 보기
6/7

이번 포스팅에서는 저번 시간에 이어 HTTP의 특징 중 HTTP 메시지에 대해 공부해보려고 한다.

[WEB 개발 기초] HTTP의 특징을 파헤치자 ① : 클라이언트-서버 아키텍처, 무상태성, 비연결성
https://velog.io/@jasmine0714/WEB-%EA%B0%9C%EB%B0%9C-%EA%B8%B0%EC%B4%88-HTTP%EC%9D%98-%ED%8A%B9%EC%A7%95%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90

HTTP 메시지는 클라이언트와 서버 간의 통신을 위해 사용되는 데이터의 구조이다. 먼저 요청 메시지와 응답 메시지 각각의 구조를 살펴보겠다. 그리고 HTTP 메시지 구조에서도 요청이나 응답의 부가 정보에 대해 설명하는 헤더의 종류가 많아서, 중요한 헤더들을 위주로 살펴보고자 한다.

1. HTTP 메시지 구조

curl -i [내가 보고싶은 웹사이트의 URL]

터미널에 이 명령어를 입력하면 HTTP 응답 메시지를 볼 수 있다.
나는 저번 시간에 포스팅했던 HTTP의 특징을 파헤치자 ① 게시물의 URL을 입력해보았다.

curl -i https://velog.io/@jasmine0714/WEB-%EA%B0%9C%EB%B0%9C-%EA%B8%B0%EC%B4%88-HTTP%EC%9D%98-%ED%8A%B9%EC%A7%95%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90/index.html


우와 짱 신기해!!!!
이렇게 직접 눈으로 보니까 신기하다 ㅎㅎㅎㅎ

근데 나는 HTTP 요청 메시지도 보고 싶은데??
curl -v 옵션을 사용하면 상세한 정보를 출력해준다고 해서 입력해보았다.

curl -v https://velog.io/@jasmine0714/WEB-%EA%B0%9C%EB%B0%9C-%EA%B8%B0%EC%B4%88-HTTP%EC%9D%98-%ED%8A%B9%EC%A7%95%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90/index.html


와.. 대박... 짱 신기.....

HTTP 요청 메시지가 보이기 전에 scheme이 HTTPS여서 TLS handshake 과정도 보이고, HTTP 버전2라서 멀티플렉싱 지원한다는 정보도 보인다. 그 다음에 GET메서드, URL, HTTP 버전 정보가 나오는 것보니까 여기서부터가 HTTP 메시지인가보군!

HTTP 요청 메시지

start-line (또는 request line)

> GET /@jasmine0714/WEB-%EA%B0%9C%EB%B0%9C-%EA%B8%B0%EC%B4%88-HTTP%EC%9D%98-%ED%8A%B9%EC%A7%95%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90/index.html HTTP/2

HTTP 요청 메서드, 요청 URL, HTTP 버전 정보가 나온다.

> Host: velog.io
> user-agent: curl/7.86.0
> accept: */*

요청이 보내지는 도메인을 나타내는 Host, 클라이언트의 브라우저 정보를 나타내는 user-agent, 클라이언트의 미디어 타입 선호도를 나타내는 accept가 header 부분에 포함되어 있다. 뒤에서 자세히 다루겠지만, 이 외에도 다양한 헤더 필드가 포함될 수 있다.

blank-line

> 

header와 body를 구분하기 위해 반드시 빈 줄이 들어간다.

body

GET 요청이므로 생략되어 있다.

HTTP 응답 메시지

start-line (또는 status line)

< HTTP/2 200 

HTTP 버전, HTTP 상태코드로 이루어져 있다.

header

< date: Sun, 21 May 2023 00:06:42 GMT
< content-type: text/html; charset=utf-8
< content-length: 125630

서버가 응답을 보낸 시각을 나타내는 date, payload의 데이터 타입을 나타내는 content-type, payload의 데이터 길이를 나타내는 content-length가 포함되어 있다. 요청 메시지와 동일하게 다양한 헤더 필드가 포함될 수 있다.

blank-line

>

요청 메시지와 마찬가지로 header와 body를 구분하기 위해 반드시 빈 줄이 들어간다.

body

<!doctype html>
<html><head><title data-rh="true">[WEB 개발 기초] HTTP의 특징을 파헤치자 ① :  클라이언트-서버 아키텍처, 무상태성, 비연결성</title><link data-rh="true" rel="canonical" href="https://velog.io/@jasmine0714/WEB-개발-기초-HTTP의-특징에-대해-알아보자"/><meta data-rh="true" property="fb:app_id" content="203040656938507"/><meta data-rh="true" name="description" content="HTTP 특징 중 3가지에 대해 먼저 알아보자. HTTP 메시지는 다뤄야 할 내용이 많으므로 다음 시간에!"/><meta data-rh="true
.
.

드디어 payload!! GET요청에 대해 서버가 보내준 payload가 실려있다. HTTP 파일이 온다. 너무 신기해 ㅋㅋㅋㅋㅋㅋ

이제 HTTP 요청/응답 메시지의 구조를 살펴봤으니, HTTP 메시지에서 헤더의 종류에 어떤 것들이 있는지 살펴보고자 한다.

2. HTTP 헤더

HTTP 전송에 필요한 모든 부가 정보를 담고 있는 부분이다. body에 있는 payload에 대한 내용인 메타 데이터, 압축, 인증, 요청 클라이언트나 응답하는 서버의 정보, 캐시 관리 등등 종류가 아주 많다.

이 포스팅에서는 그 중에서도 표현 헤더, 협상 헤더, 쿠키 헤더 이렇게 3가지에 대해 다루겠다.

표현 헤더

말 그대로 페이로드가 어떤 데이터인지 표현하는 메타데이터를 담는 헤더이다.

- Content-Type: 표현 데이터의 형식

페이로드가 어떤 형식을 가지고 있는지를 나타낸다. 미디어 타입이나 문자 인코딩 등을 설명한다.

위에서 본 나의 블로그 포스팅 페이지에 대한 HTTP 응답 메시지에도

content-type: text/html; charset=utf-8

content-type 헤더 필더가 있다.
미디어 타입은 html, 문자 인코딩은 utf-8로 되어 있다는 의미이다.

이 밖에도 application/json, image/png 등 페이로드의 형식에 따라 다양하게 나타날 수 있다.

- Content-Encoding: 표현 데이터의 압축 방식

HTTP 응답을 받았을 때 페이로드가 압축이 되어있는 경우가 있다. 이 때 어떤 방식으로 압축이 되어있는지 알아야만 데이터를 읽는 쪽에서 압축을 해제할 수 있으므로, 헤더에 압축 정보를 같이 기재해준다.

gzip, deflate, identity가 대표적인 예시라고 한다.
identity는 압축을 안한다는 뜻!

- Content-Language: 표현 데이터의 자연 언어

표현 데이터가 한국어인지, 영어인지 등등 자연 언어를 나타내는 헤더이다.
ko, en 등이 포함된다.

- Content-Length: 표현 데이터의 길이

오오 내 블로그 포스팅 응답 메시지에도 이 헤더 필더 있어~~

content-length: 125630

이 숫자는 바이트 단위라고 한다. 페이로드가 125630 바이트나 된단 말이야??! 열심히 쓰긴 했나보군 ㅎㅎㅎㅎ

협상 헤더

클라이언트가 서버에게 표현 협상을 요청할 때 사용하는 헤더이다. 그래서 클라이언트가 요청할 때만 사용한다.

어잉? 근데 위의 예시에서는 HTTP 요청 메시지에 협상 헤더는 > accept: */* 하나 밖에 안 보이네?
curl 명령어를 이용하더라도 모든 헤더가 다 출력되는 것은 아니라고 한다. 그래서 개발자 도구의 네트워크 탭을 확인해보았다.

accept, accept-encoding, accept language가 보인다. 협상 헤더에서는 quality values를 사용하여 여러 옵션에 대해 클라이언트의 상대적 선호도를 나타낼 수 있다.

- Accept: 클라이언트가 선호하는 미디어 타입 전달

accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7

각 미디어 타입 별로 상대적인 선호도가 q=숫자 의 형식으로 나타나고 있다. 숫자는 0~1의 사이에서 나타날 수 있고, 생략될 경우 1이라는 의미이다.

- Accept-encoding: 클라이언트가 선호하는 압축 인코딩

accept-encoding: gzip, deflate, br

클라이언트가 gzip, deflate, br 방식의 압축을 선호한다는 의미이다.

- Accept-language: 클라이언트가 선호하는 자연 언어

클라이언트가 원하는 자연 언어가 반드시 지원되는 것은 아니기 때문에, 자연 언어의 상대적인 선호도를 quality values(q)를 이용하여 나타낼 수 있다.

위의 사진 예시에서 볼 수 있듯이,

accept-language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7

미디어 타입과 마찬가지로, 각 언어 별로 상대적인 선호도가 q=숫자 의 형식으로 나타나고 있다. 숫자는 0~1의 사이에서 나타날 수 있고, 생략될 경우 1이라는 의미이다.

쿠키 헤더

저번 포스팅에서 미리 한 번 살펴봤던 쿠키 재등장! 서버가 클라이언트에 데이터를 저장하기 위해 쿠키를 전송해 놓으면, 클라이언트가 이후에 특정 리소스에 대한 접근 권한에 대해 인가를 받기 위해 서버에 쿠키를 전송하는 구조이다.

서버가 쿠키를 생성할 때에는 쿠키 옵션을 지정하는데, 이 쿠키 옵션들이 set-Cookie라는 프로퍼티에 담겨서 쿠키 헤더에 포함되어 전송된다.

  const cookiesOption = {
    domain: "localhost",
    path: "/",
    maxAge: 3600,
    // 또는 expires: new Date("2023-05-31").toUTCString(),
    secure: true,
    httpOnly: true,
    sameSite: "strict",
  };

- Domain: 클라이언트가 쿠키를 전송할 수 있는 도메인 제한

쿠키 옵션에 도메인 정보가 존재하면, 쿠키에 표시된 도메인 옵션과 서버의 도메인이 일치해야만 클라이언트가 서버에 쿠키를 전송할 수 있다. 만약 도메인 옵션을 지정하지 않으면 클라이언트가 어떤 서버에든 쿠키를 전송할 수 있게 되어 보안 문제가 생길 수 있다. 예를 들어서 만약 네이버 서버에서 클라이언트에게 쿠키를 전송해줬는데 도메인 옵션이 없다면, 클라이언트가 구글 서버에 네이버 서버로부터 받은 쿠키를 전송할 수도 있게 된다.

- Path: 클라이언트가 쿠키를 전송할 수 있는 세부 경로 지정

명시하지 않으면 기본적으로 "/"로 지정되어 있다.
path를 지정하면, 해당 path를 포함한 하위 경로들에서만 서버에게 쿠키를 전송할 수 있다.

예를 들어, http://www.localhost.com:3000/users/로 path를 지정해 놓았다고 가정해보자. 이때 http://www.localhost.com:3000/users/login에서는 쿠키 전송이 가능하지만, http://www.localhost.com:3000/main에서는 쿠키 전송이 불가능하다.

- Max-age 또는 Expire: 쿠키의 유효기간 지정

쿠키의 유효기간을 설정하지 않으면 보안 측면에서 취약할 수 있다. 따라서 일정 기간이 지나면 쿠키를 소멸시켜야 하며, 이 때 쿠키의 유효기간을 정할 때 Max-age 또는 Expire를 지정할 수 있다.

  • 영속성 쿠키
    Max-age 또는 Expire 옵션이 있으면 유효기간이 지정되어 있는 쿠키이므로, 브라우저를 종료해도 쿠키가 삭제되지 않고 남아있다. 이처럼 유효기간이 명시되어 있는 쿠키를 '영속성 쿠키'라고 한다.

    • Max-age: 쿠키가 생성된 후 '몇 초' 동안 유지될지 설정한다. 예를 들어 max-age: 3600은 3600초(1시간 = 60 * 60)동안 유지되도록 설정한다는 의미이다.
    • expires: 쿠키의 만료일자를 지정한다. 예를 들어 expires: new Date("2023-05-31").toUTCString()은 쿠키를 2023년 5월 31일까지 유지시킨다는 의미이다.
  • 세션 쿠키
    영속성 쿠키와 달리 Max-age, Expire 옵션이 없어서 브라우저를 종료하면 삭제되는 쿠키이다.

- Secure: HTTPS를 이용할 때만 서버에 쿠키 전송 가능한가

서버 URL의 프로토콜이 HTTPS인 경우에만 클라이언트가 쿠키를 보낼 수 있도록 지정하는 옵션이다. Secure 옵션이 없으면 HTTP인 경우에도 쿠키를 보낼 수 있다.
(domain이 localhost일 경우에는 Secure 옵션을 별도로 설정하지 않아도 예외적으로 쿠키 전송이 가능하다고 한다.)

- HTTPOnly: 자바스크립트로 브라우저 쿠키에 접근 가능한가

이거슨 반드시 true로 설정해줘야 하는 옵션!! XSS 공격으로 쿠키가 탈취될 위험이 있으므로 자바스크립트로 쿠키에 접근이 불가능하게 해야 한다.

- sameSite: Cross-Site 요청일 때 쿠키를 전송할 수 있는가

먼저 Cross-Site이 무엇인지부터 알아보자.
Cross-Site: eTLD+1이 다를 경우
아니 그럼 eTLD+1은 무엇이냐
TLD(Top Level Domain)란 .com, .org처럼 도메인의 가장 마지막 부분을 의미하고, eTLD+1은 바로 왼쪽의 주소를 하나 더 합한 것을 의미한다.
단 .io의 경우 예외적으로 왼쪽의 주소를 하나 더 합한 것까지를 TLD로 보고, 왼쪽의 주소를 하나 더 합해야 eTLD+1가 된다.

예를 들어서 위키백과에 쿠키를 검색했을 때

쿠키에는 참 많은 의미가 있군..
여튼 URL을 보면

https://ko.wikipedia.org/wiki/%EC%BF%A0%ED%82%A4_(%EB%8F%99%EC%9D%8C%EC%9D%B4%EC%9D%98)

org가 TLD가 되고, eTLD+1은 wikipedia.org가 되는 것이다.

이 eTLD+1이 다른 경우에 Cross-Site으로 보는 것이다!

Cross-Site이면 쿠키를 전송할 수 있는지를 서버에서 cookie를 생성할 때 option에 기재해서 헤더에 담아 날려주는 것이다.

Strict로 기재할 경우 가장 엄격하게 Cross-Site의 경우 쿠키 전송을 막는 옵션이고,
None으로 기재할 경우 가장 느슨한 옵션으로 항상 쿠키를 전송할 수 있다. (다만 이 때 Secure 옵션이 True로 설정되어야 한다. 즉 적어도 서버 도메인이 HTTPS를 사용하고 있어야 한다.)
Lax 옵션도 있는데, 이건 GET 메서드일 때만 쿠키 전송이 가능하게 하는 것이다.

이러한 옵션들을 set-cookie에 옵션으로 설정하여 헤더에 담아 클라이언트의 상태정보를 브라우저에 저장하도록 슝슝 날려준다.

드디어 HTTP 메시지에 대한 포스팅도 완료!! 특히 쿠키 부분이 어려웠는데, 앞에서 한 번 쿠키, 세션, 토큰을 정리하고 와서 좀 더 공부하기가 수월해진 것 같다. ㅎㅎㅎ 아주 굳! 이제 디자인 시스템 공부하러 가쟝 짜이찌앤~~~

profile
기록에 진심인 개발자 🌿

0개의 댓글