혼자 공부하는 네트워크책을 읽으면서 배운 점을 정리합니다.HTTP는 스테이트리스 프로토콜이지만 쿠키를 통해 상태를 유지할 수 있고, 캐시를 통해 성능을 향상시킬 수 있다. 또한 SSL/TLS를 통해 보안 통신을 구현하는 HTTPS가 오늘날 웹의 표준이 되었다. 이 글에서는 HTTP 기반의 핵심 응용 기술들을 정리해본다.
1️⃣ 쿠키
쿠키의 필요성
1-1 스테이트리스의 한계
HTTP는 기본적으로 스테이트리스(Stateless) 프로토콜이기 때문에 모든 HTTP 요청 메시지는 독립된 메시지로 간주된다. 그런데 웹 서비스를 이용하다 보면 다음과 같은 기능들을 자주 접하게 된다.
- "3일간 보지 않기" 팝업
- 로그인 상태 유지
- 장바구니 기능
- 사용자 선호 설정 기억
이런 기능들은 분명 클라이언트의 상태를 알고 있어야 구현이 가능하다. 모든 클라이언트의 요청을 독립적인 메시지로 간주한다면 구현할 수 없을 것이다.
HTTP 쿠키(HTTP Cookie) 또는 단순히 쿠키(Cookie)를 활용하면 이와 같은 기능을 구현할 수 있다.
1-2 쿠키의 개념
쿠키는 HTTP의 스테이트리스한 특성을 보완하기 위한 대표적 수단으로, 서버에서 생성되어 클라이언트 측에 저장되는 <이름, 값> 쌍 형태의 데이터이다.
이름=값
이름=값; 속성1
이름=값; 속성1; 속성2쿠키는 이름과 값 이외에도 쿠키의 만료 기간과 같은 추가적인 속성값도 가질 수 있다. 클라이언트는 서버로부터 받은 쿠키를 주로 브라우저에 저장한다.
브라우저에서 쿠키 확인하기
크롬 브라우저의 경우 [개발자 도구] → [Application] → [Storage] → [Cookies] 항목에서 저장된 쿠키를 확인할 수 있다.
| 쿠키 정보 | 설명 |
|---|---|
| Name | 쿠키의 이름 |
| Value | 쿠키의 값 |
| Domain | 쿠키가 유효한 도메인 |
| Path | 쿠키가 유효한 경로 |
| Expires / Max-Age | 쿠키의 만료 시점 또는 유효 기간 |
| HttpOnly | JavaScript 접근 제한 여부 |
| Secure | HTTPS에서만 전송 여부 |
쿠키의 송수신
1-3 Set-Cookie 헤더
서버는 쿠키를 생성하여 클라이언트에 전송하고, 클라이언트는 쿠키를 저장해 두었다가 추후 같은 서버에 요청을 보낼 때 요청 메시지에 쿠키를 포함하여 전송한다.
서버가 클라이언트에게 쿠키를 전송할 때는 응답 메시지의 Set-Cookie 헤더가 활용된다.
Set-Cookie 헤더 형식
Set-Cookie: 이름=값
Set-Cookie: 이름=값; 속성1
Set-Cookie: 이름=값; 속성1; 속성2응답 메시지 예시
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: name=minchul
Set-Cookie: phone=100-100
Set-Cookie: message=Hello쿠키의 이름과 값, 때로는 세미콜론(;)으로 구분한 쿠키의 속성이 명시될 수 있다. 여러 쿠키를 전달할 때는 여러 개의 Set-Cookie 헤더가 사용된다.
1-4 Cookie 헤더
클라이언트가 서버에게 쿠키를 건넬 때는 Cookie 헤더가 활용된다.
Cookie 헤더 형식
Cookie: 이름=값; 이름=값; ...요청 메시지 예시
GET /next_page HTTP/1.1
Host: example.com
Cookie: name=minchul; phone=100-100; message=Hello서버에 여러 쿠키를 전달할 때는 세미콜론(;)으로 여러 쿠키의 <이름, 값> 쌍을 구분한다.
💡 쿠키의 자동 전송
특정 서버로부터 쿠키를 전달받았다면 다음부터 해당 서버에 요청을 보낼 때 전달받은 쿠키를 자동으로 전송한다. 즉, 어떤 서버로부터 쿠키를 전달받으면 해당 서버에 보내는 요청 메시지에는 자동으로 전달받은 쿠키가 포함된다.
쿠키의 속성
1-5 Domain과 Path
쿠키는 Domain과 Path 속성을 통해 쿠키를 전송할 도메인과 경로를 제한할 수 있다.
Set-Cookie: name=minchul; Domain=minchul.net
Set-Cookie: name=minchul; Path=/lectures- Domain: 쿠키를 사용할 도메인 지정
- Path: 쿠키를 사용할 경로 지정
1-6 Expires와 Max-Age
쿠키의 유효기간을 설정하는 속성이다.
Set-Cookie: sessionID=abc123; Expires=Fri, 23 Aug 2024 09:00:00 GMT
Set-Cookie: sessionID=abc123; Max-Age=2592000| 속성 | 설명 |
|---|---|
| Expires | 쿠키 만료 시점 (요일, DD-MM-YY HH:MM:SS GMT 형식) |
| Max-Age | 초 단위 유효기간 |
Expires로 명시된 시점이 지나거나 Max-Age로 명시된 유효기간이 지나면 해당 쿠키는 삭제되어 전달되지 않는다.
1-7 보안 속성
Secure
Secure 속성은 HTTPS를 통해서만 쿠키를 송수신하도록 하는 속성이다.
Set-Cookie: sessionID=abc123; SecureHTTP의 더 안전한 방식인 HTTPS를 통해서만 쿠키가 전송되므로 보안을 강화할 수 있다.
HttpOnly
HttpOnly 속성은 JavaScript를 통한 쿠키의 접근을 제한하고, 오직 HTTP 송수신을 통해서만(HTTP 헤더를 주고받는 방식으로만) 쿠키에 접근하도록 하는 방식이다.
Set-Cookie: sessionID=abc123; HttpOnly이를 통해 XSS(Cross-Site Scripting) 공격으로부터 쿠키를 보호할 수 있다.
// HttpOnly 속성이 없으면 JavaScript로 접근 가능
document.cookie // 쿠키 접근 가능
// HttpOnly 속성이 있으면 JavaScript로 접근 불가
document.cookie // HttpOnly 쿠키는 접근 불가💡 웹 스토리지: 로컬 스토리지와 세션 스토리지
쿠키 이외에도 클라이언트의 상태를 저장할 수 있는
<키, 값>쌍 형태의 정보가 있다. 바로웹 스토리지(Web Storage)이다.웹 스토리지의 특징
- 웹 브라우저 내의 저장 공간
- 일반적으로 쿠키보다 더 큰 데이터 저장 가능
- 서버로 자동 전송되지 않음 (쿠키와의 주요 차이점)
로컬 스토리지 vs 세션 스토리지
종류 설명 로컬 스토리지 별도로 삭제하지 않는 한 영구적으로 저장 세션 스토리지 세션이 유지되는 동안(브라우저가 열려 있는 동안) 유지 브라우저 개발자 도구의 **[Application] → [Storage]**에서 확인할 수 있다.
2️⃣ 캐시
캐시의 개념
2-1 HTTP 캐시란
HTTP 캐시(HTTP Cache) 또는 웹 캐시(Web Cache)는 응답받은 자원의 사본을 임시 저장하여 불필요한 대역폭 낭비와 응답 지연을 방지하는 기술이다.
클라이언트가 서버로부터 10MB 크기의 이미지를 전달받았다고 가정하자. 이 자원의 사본을 임시 저장하면 추후 동일한 요청 메시지를 보내야 할 때 임시 저장된 사본을 재활용할 수 있고, 결과적으로 더 빠르게 자원에 접근할 수 있다.
💡 캐시의 종류
- 개인 전용 캐시(Private Cache): 클라이언트(주로 웹 브라우저)에 저장
- 공용 캐시(Public Cache): 클라이언트와 서버 사이에 위치한 중간 서버에 저장
캐시의 유효기간
2-2 Expires와 Cache-Control
대부분의 캐시된 데이터에는 유효기간이 설정되어 있다. 캐시할 데이터에 유효기간을 부여하기 위해 응답 메시지의 Expires 헤더와 Cache-Control 헤더의 Max-Age 값을 사용할 수 있다.
Expires 헤더
캐시한 데이터의 만료 날짜를 명시한다.
HTTP/1.1 200 OK
Date: Mon, 05 Feb 2024 12:00:00 GMT
Content-Type: text/plain
Content-Length: 100
Expires: Tue, 06 Feb 2024 12:00:00 GMTCache-Control 헤더
캐시하여 사용 가능한 초 단위 시간을 명시한다.
HTTP/1.1 200 OK
Date: Mon, 05 Feb 2024 12:00:00 GMT
Content-Type: text/plain
Content-Length: 100
Cache-Control: max-age=1200클라이언트가 응답받은 자원을 임시 저장하여 이용하다가 유효기간이 만료되면 다시 서버에 자원을 요청해야 한다.
2-3 캐시 신선도
캐시에 유효기간이 부여되는 근본적인 이유는 클라이언트가 캐시를 참조하는 사이 서버의 원본 데이터가 변경되어 원본 데이터와 캐시된 사본 데이터 간의 일관성이 깨질 수 있기 때문이다.
캐시 신선도(Cache Freshness)는 캐시된 사본 데이터가 서버의 원본 데이터와 얼마나 유사한지의 정도를 나타낸다.
- 캐시의 유효기간을 설정하고 만료된 자원을 재요청함으로써 캐시 신선도를 검사
- 원본 데이터가 변경되었을 때 해당 자원을 다시 응답받음으로써 캐시 신선도를 높게 유지
캐시 검증
2-4 If-Modified-Since 헤더
캐시의 유효기간이 만료되었더라도 서버의 원본 데이터가 변하지 않았을 수 있다. 이런 경우에는 굳이 서버로부터 같은 자원을 다시 전달받을 필요가 없다. 그저 캐시의 유효기간을 연장하여 이용하면 된다.
클라이언트는 캐시된 자원의 유효기간이 만료되었을 때, 서버에게 원본 자원이 변경된 적이 있는지를 질의한다.
If-Modified-Since 헤더는 날짜를 기반으로 원본 자원의 변경 여부를 묻는 헤더이다.
요청 메시지 예시
GET /index.html HTTP/1.1
Host: www.example.com
If-Modified-Since: Fri, 23 Aug 2024 09:00:00 GMT이 시점 이후로 원본 자원에 변경이 있었다면 그때만 변경된 자원을 메시지 본문으로 응답하도록 서버에게 요청한다.
서버의 응답
If-Modified-Since 헤더를 받은 서버는 다음 3가지 중 하나로 응답한다.
① 서버가 요청받은 자원이 변경된 경우
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1234
Last-Modified: Mon, 25 Aug 2024 10:00:00 GMT
<!DOCTYPE html>
<html>
...
</html>서버는 200 (OK)과 함께 새로운 자원을 반환한다.
② 서버가 요청받은 자원이 변경되지 않은 경우
HTTP/1.1 304 Not Modified
Last-Modified: Fri, 23 Aug 2024 09:00:00 GMT서버는 메시지 본문 없이 304 (Not Modified)를 통해 클라이언트에게 '자원이 변경되지 않았음'을 알린다. 이 경우 클라이언트는 캐시된 자원을 사용할 수 있다.
Last-Modified 헤더로 자원의 마지막 변경 시점을 알릴 수 있다.
③ 서버가 요청받은 자원이 삭제된 경우
HTTP/1.1 404 Not Found서버는 404 (Not Found)를 통해 요청한 '자원이 존재하지 않음'을 알린다.
💡 304 Not Modified
'캐시된 자원을 참조하라'는 의미의 상태 코드
304 (Not Modified)는 가장 흔히 볼 수 있는 상태 코드 중 하나이다.
2-5 If-None-Match 헤더와 ETag
클라이언트가 서버에게 원본 자원의 변경 여부를 묻기 위해 날짜가 아닌 엔티티 태그를 기반으로 물어볼 수도 있다.
ETag(Entity Tag)는 자원의 버전을 식별하기 위한 정보를 말한다.
- 자원이 변경될 때마다 ETag 값이 변경
- 자원이 변경되지 않았다면 ETag 값도 변경되지 않음
따라서 서버에 특정 자원의 ETag 값이 변경되었는지를 물음으로써 자원의 변경 여부도 알 수 있다.
If-None-Match 헤더
If-None-Match 헤더에는 요청할 자원에 대한 ETag 값이 명시된다. 명시된 ETag 값과 일치하는 ETag가 없다면(자원이 변경되어 ETag 값도 변경되었다면) 그때만 변경된 자원으로 응답하도록 서버에게 요청한다.
요청 메시지 예시
GET /index.html HTTP/1.1
Host: www.example.com
If-None-Match: "abc123"서버의 응답
If-None-Match 헤더를 받은 서버는 다음 3가지 중 하나로 응답한다.
① 서버가 요청받은 자원이 변경된 경우
서버는 200 (OK)과 함께 새로운 자원을 반환한다.
② 서버가 요청받은 자원이 변경되지 않은 경우
서버는 메시지 본문 없이 304 (Not Modified)를 통해 '자원이 변경되지 않았음'을 알린다. 클라이언트는 캐시된 자원을 사용할 수 있다.
③ 서버가 요청받은 자원이 삭제된 경우
서버는 404 (Not Found)를 통해 '자원이 존재하지 않음'을 알린다.
3️⃣ 콘텐츠 협상
자원의 표현
3-1 표현(Representation)의 개념
서버와 클라이언트가 HTTP 메시지를 통해 주고받는 것을 '자원'이라고 설명했지만, 조금 더 엄밀하게 말하면 자원의 표현이다.
표현(Representation)이란 송수신 가능한 자원의 형태를 의미한다.
같은 자원에 대해서도 여러 가지 표현이 있을 수 있다. 예를 들어 'computer science를 검색한 결과'라는 동일한 자원을 요청했더라도:
- 한국어로 표현된 자원이 응답될 때
- 영어로 표현된 자원이 응답될 때
즉, 같은 URI(URL)에 대해서도 다른 자원의 표현이 있을 수 있다.
💡 GET 메서드의 정확한 목적
GET 메서드의 정확한 목적은 '자원 조회'보다는 자원의 특정 표현 조회에 가깝다.
콘텐츠 협상 헤더
3-2 콘텐츠 협상이란
같은 자원에 대해 할 수 있는 여러 표현 중 클라이언트가 가장 적합한 자원의 표현을 제공하는 기술을 콘텐츠 협상(Content Negotiation)이라고 한다.
자원에 대한 다양한 표현 중 클라이언트가 선호하는 자원의 표현을 콘텐츠 협상 헤더를 통해 서버에게 전송하면 서버는 클라이언트가 요청한 자원의 표현을 응답한다.
대표적인 콘텐츠 협상 헤더
| 헤더 | 설명 |
|---|---|
| Accept | 선호하는 미디어 타입 |
| Accept-Language | 선호하는 언어 |
| Accept-Encoding | 선호하는 인코딩 방식 |
요청 메시지 예시
GET /index.html HTTP/1.1
Host: example.com
Accept-Language: ko
Accept: text/html3-3 우선순위와 Quality Value
클라이언트가 우선순위를 반영하여 여러 표현에 대한 선호도를 서버에 알릴 수도 있다.
예를 들어:
- "언어는 한국어를 가장 선호하지만, 영어도 받을 용의가 있다"
- "미디어 타입은 HTML 문서를 가장 선호하지만, XML을 그 다음으로 선호하고, 일반 텍스트를 그 다음으로 선호한다"
이러한 우선순위는 콘텐츠 협상 관련 헤더의 q값으로 표현된다.
Quality Value (q)
- q: Quality Value의 약자
- 범위: 0부터 1까지
- 기본값: 1 (생략 시)
- 우선순위: 값이 클수록 높음
우선순위 예시
GET /index.html HTTP/1.1
Host: example.com
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7
Accept: text/html,application/xml;q=0.9,text/plain;q=0.6,*/*;q=0.5Accept-Language 해석
ko-KR(q=1.0, 생략): 한국(KR)의 한국어를 가장 선호ko;q=0.9: 한국어를 두 번째로 선호en-US;q=0.8: 미국 영어를 세 번째로 선호en;q=0.7: 영어를 네 번째로 선호
Accept 해석
text/html(q=1.0, 생략): HTML을 가장 선호application/xml;q=0.9: XML을 두 번째로 선호text/plain;q=0.6: 일반 텍스트를 세 번째로 선호*/*;q=0.5: 모든 타입을 네 번째로 선호
4️⃣ 보안: SSL/TLS와 HTTPS
HTTPS의 개념
4-1 HTTPS란
오늘날 많은 웹 서비스는 HTTP에 안전성을 더한 프로토콜인 HTTPS(HTTP Secure, HTTP over TLS)로 동작한다.
정확히 말하자면, HTTPS는 HTTP에 SSL 혹은 TLS라는 프로토콜의 동작이 추가된 프로토콜이다.
웹 브라우저에서 도메인 네임 좌측의 자물쇠 모양 아이콘을 볼 수 있다. 이는 해당 사이트가 HTTPS를 사용한다는 의미로, 해당 웹사이트와 브라우저 간에 SSL/TLS 기반 암호화 통신이 이루어진다는 점을 시사한다.
🔒 https://www.example.com4-2 SSL과 TLS
SSL(Secure Sockets Layer)과 TLS(Transport Layer Security)는 모두 인증과 암호화를 수행하는 프로토콜이다.
- TLS: SSL을 계승한 프로토콜
- SSL과 TLS의 작동 과정은 세부적인 차이가 있을 수 있지만 큰 틀에서는 유사
버전의 발전
| 버전 | 설명 |
|---|---|
| SSL 2.0, 3.0 | 초기 버전 (현재 사용 중단) |
| TLS 1.0, 1.1 | SSL을 계승한 초기 TLS 버전 |
| TLS 1.2, 1.3 | 오늘날 주로 사용되는 버전 |
상대적으로 최근에 출시된 TLS 1.3의 비중이 커지고 있다.
HTTPS의 동작 과정
4-3 HTTPS 메시지 송수신 단계
TLS 1.3 기반 HTTPS 메시지는 크게 다음과 같은 단계를 거쳐 송수신된다.
1. TCP 쓰리 웨이 핸드셰이크
2. TLS 핸드셰이크
3. 메시지 송수신HTTPS 메시지 송수신은 일반적인 HTTP 메시지 송수신에 TLS 핸드셰이크가 더해진 것이다. TLS 핸드셰이크 과정을 거쳐 (서로에 대한 인증과 더불어) 메시지 암호화가 이루어지므로 이후 주고받는 메시지는 암호화된 메시지이다.
TLS 핸드셰이크
4-4 TLS 핸드셰이크 과정
TLS 핸드셰이크는 다음과 같은 메시지를 주고받는 과정을 의미한다. TLS 핸드셰이크의 핵심 내용은 크게 2가지이다.
- 암호화 통신을 위한 키를 생성/교환
- 인증서 송수신과 검증
4-5 암호화 키의 생성과 교환
암호화 알고리즘과 키
암호화 알고리즘을 통해 평문을 암호화하거나 암호문을 복호화하려면 키(Key)라는 정보가 필요하다.
평문 + 암호화 알고리즘 + 키 = 암호문
암호문 + 복호화 알고리즘 + 키 = 평문키는 암호화 통신을 수행하는 두 호스트만 알고 있어야 하는 정보로, TLS 핸드셰이크 과정에서 ClientHello 메시지, ServerHello 메시지를 주고받으며 생성/교환된다.
ClientHello 메시지
클라이언트는 ClientHello 메시지를 보낸다. 이 메시지는 암호화된 통신을 위해 서로 맞춰 봐야 할 정보들을 제시하는 메시지이다.
ClientHello 메시지 포함 내용
- 지원되는 TLS 버전
- 사용 가능한 암호화 알고리즘과 해시 함수
- 키를 만들기 위해 사용할 클라이언트의 난수
암호 스위트(Cipher Suite)
클라이언트는 '사용 가능한 암호화 알고리즘과 해시 함수'를 서버에 알리기 위해 ClientHello 메시지에 암호 스위트(Cipher Suite)를 포함하여 전송한다.
한 줄 한 줄이 암호화 알고리즘과 해시 함수의 종류를 나타낸다.
ServerHello 메시지
서버는 ClientHello 메시지에 대한 응답으로 ServerHello 메시지를 전송한다.
- ClientHello: 암호화 이전에 맞춰 봐야 할 정보들을 제시
- ServerHello: 제시된 정보들을 선택
ServerHello 메시지 포함 내용
- 선택된 TLS 버전
- 선택된 암호 스위트
- 키를 만들기 위해 사용할 서버의 난수
ClientHello 메시지와 ServerHello 메시지를 주고받으면 암호화된 통신을 위해 사전 협의해야 할 정보들이 결정되고, 결정된 정보를 토대로 서버와 클라이언트가 암호화에 사용할 키를 만들어 암호화에 사용할 수 있다.
4-6 인증서의 송수신과 검증
인증서(Certificate)란
인증서(Certificate) 또는 정확하게는 공개 키 인증서(Public Key Certificate)는 당신이 통신을 주고받는 상대방은 틀림없이 당신이 의도한 대상이 맞다라는 사실을 입증하기 위한 정보이다.
예를 들어 인증서는 www.hanbit.co.kr이라는 호스트와 메시지를 주고받을 때, 송수신하는 대상은 틀림없이 www.hanbit.co.kr이라고 보장하기 위한 정보이다.
인증 기관(CA)
송수신하는 당사자가 "내가 맞다"는 사실을 보장하면 아무런 의미가 없다. 제3의 기관이 보장해야 한다.
CA(Certificate Authority) 또는 인증 기관은 인증서의 발급과 검증, 저장 등의 역할을 수행하는 공인 기관이다.
주요 CA
- DigiCert
- GlobalSign
- Let's Encrypt
- 등
Certificate와 CertificateVerify 메시지
TLS 핸드셰이크에서 인증서 및 인증서 검증과 관련한 메시지는 다음과 같다.
| 메시지 | 설명 |
|---|---|
| Certificate | 인증서 내용 포함 (인증서 서명 값 등) |
| CertificateVerify | 인증서의 내용이 올바른지 검증하기 위한 메시지 |
서버와 클라이언트는 암호화에 사용할 키를 획득하고, 서로가 틀림없다는 사실까지 인증했다.
4-7 Finished 메시지와 메시지 송수신
서버와 클라이언트는 마지막으로 TLS 핸드셰이크의 마지막을 의미하는 Finished 메시지를 주고받는다.
이후부터 서버와 클라이언트는 암호화된 HTTP 메시지를 주고받을 수 있다.
5️⃣ 정리
-
쿠키는 HTTP의스테이트리스한 특성을 보완하여 로그인 상태 유지, 사용자 선호 설정 기억 등의 기능을 구현할 수 있게 한다.Set-Cookie와Cookie헤더를 통해 서버와 클라이언트 간 쿠키를 주고받으며, Domain, Path, Expires, Max-Age, Secure, HttpOnly 등의 속성으로 쿠키의 동작을 제어한다. -
캐시는 응답받은자원의 사본을임시 저장하여 불필요한 대역폭 낭비와 응답 지연을 방지한다.Expires와Cache-Control헤더로 캐시의 유효기간을 설정하고,If-Modified-Since와If-None-Match헤더로 캐시의 신선도를 검증하여 효율적인 자원 관리가 가능하다. -
콘텐츠 협상은 같은 자원에 대한 여러 표현 중 클라이언트가 가장 적합한 표현을 제공받을 수 있게 한다. Accept, Accept-Language, Accept-Encoding 헤더와 Quality Value를 통해 클라이언트의 선호도를 서버에 전달할 수 있다.
-
HTTPS는HTTP에SSL/TLS를 추가하여 안전한 통신을 제공한다.TLS 핸드셰이크를 통해암호화 키를 생성/교환하고인증서를 통해 상대방을 검증함으로써, 오늘날 웹의 표준 보안 프로토콜로 자리잡았다.