RFC 실전 교과서
패킷이 목적지에 닿는 순간부터 API가 오류를 돌려주는 방식까지, 웹을 이루는 RFC를 계층별로 묶었습니다. 각 장은 개념 설명, 직접 조작하는 실습, RFC 목록 순서로 이어집니다. 목록의 제목은 한국어 의역이고 원제는 바로 아래에 있습니다.
목차 열기
§ 0
RFC 읽는 법
RFC(Request for Comments)는 IETF와 관련 기관이 펴내는 인터넷 기술 문서 시리즈입니다. 이름과 달리 한번 발행된 RFC는 절대 수정되지 않습니다. 고칠 내용이 생기면 새 번호로 다시 냅니다. 그래서 RFC를 펼치면 가장 먼저 “이 문서가 아직 유효한가”를 확인해야 합니다. HTTP/1.1을 설명하며 RFC 2616을 인용하는 글은 2014년 이후로 낡은 정보입니다.
문서를 열면 확인할 순서
- Category: 첫 페이지 왼쪽 위. 표준 트랙(Standards Track)인지, 정보성(Informational)인지 봅니다.
- Obsoletes / Updates: 이 문서가 대체하거나 일부 고친 RFC. 반대로 rfc-editor.org 페이지의 Obsoleted by는 이 문서를 대체한 후속 RFC입니다.
- Errata: 발행 후 발견된 오류 목록. 구현자라면 꼭 확인합니다.
- 요구 수준 키워드: 대문자 MUST, SHOULD, MAY가 필수와 권장을 가릅니다(RFC 2119, 8174).
- Security Considerations: 모든 RFC에 있는 절. 구현할 때 빠지기 쉬운 함정 목록으로 읽으면 좋습니다.
상태 표시
RFC 계보 찾기
옛 RFC 번호를 넣으면 지금 읽어야 할 문서까지의 대체 흐름을 보여줍니다. 아래 칩을 눌러 주요 계보를 볼 수도 있습니다.
0.1표준화 절차와 키워드
0.2명세 작성 도구
헤더 문법(ABNF)과 레지스트리 등록 정책을 알면 HTTP 명세를 훨씬 빨리 읽을 수 있습니다.
0.3설계 철학
0.4만우절 RFC
§ 1
네트워크 기반
웹 요청 하나는 아래에서부터 IP, TCP나 UDP, 암호화 계층, HTTP 순으로 쌓입니다. HTTP/3는 TCP 대신 UDP 위의 QUIC을 쓰기 때문에 두 갈래가 생깁니다. 이 장은 아래쪽 네 층, 즉 패킷이 목적지에 닿고 연결이 열리기까지를 다룹니다.
1.1IP와 주소
IP는 “최선을 다해 전달”만 약속합니다. 순서, 중복, 손실은 위층이 책임집니다. 주소 대역의 의미를 알면 클라우드 VPC와 방화벽 설정이 쉬워집니다.
CIDR 계산기
RFC 4632 · 1918 · 6598 · 57371.2TCP와 UDP
TCP는 1981년 RFC 793 이후 40년간 수십 개 RFC로 흩어진 내용을 2022년 RFC 9293 하나로 합쳤습니다. 연결의 시작과 끝을 단계별로 따라가 봅시다.
TCP 연결의 일생
RFC 92931.3QUIC
QUIC은 TCP와 TLS가 각각 하던 일을 한 번의 핸드셰이크로 처리합니다. 첫 응답 바이트까지 몇 번의 왕복(RTT)이 드는지 비교하면 차이가 분명해집니다.
첫 응답까지 걸리는 시간
DNS 조회 시간은 빼고, HTTP 요청 1회의 왕복을 포함했습니다. 0-RTT는 이전에 접속해 세션 티켓이 있을 때만 가능하고, 재전송 공격 위험 때문에 안전한 요청(GET 등)에만 씁니다(RFC 8470).
1.4연결 수립 전략
IPv6가 고장 난 네트워크에서 사용자가 오래 기다리지 않도록 브라우저와 OS는 IPv6와 IPv4 연결을 경쟁시킵니다.
1.5DNS
DNS는 1987년 명세(1034, 1035) 위에 수십 년간 확장이 쌓였습니다. 최근 흐름은 암호화(DoT, DoH, DoQ)와 접속 정보 사전 배포(HTTPS 레코드)입니다.
이름 하나를 찾아가는 길
RFC 1034 · 10351.6실시간 통신과 WebSocket
1.7시간과 로그
토큰 만료, OTP, 인증서 검증은 모두 시계가 맞다는 전제 위에 있습니다.
1.8이메일
서비스가 가입 확인 메일 하나만 보내도 SPF, DKIM, DMARC를 맞춰야 스팸함을 피합니다.
§ 2
HTTP
2022년 6월, HTTP 명세가 크게 재편됐습니다. 버전과 무관한 의미론(9110), 캐싱(9111), HTTP/1.1 메시지 문법(9112)이 분리되었고, HTTP/2(9113)와 HTTP/3(9114)는 같은 의미론을 다른 방식으로 실어 나르는 문서가 됐습니다. 상태 코드나 메서드의 의미가 궁금하면 이제 9110 하나만 보면 됩니다.
2.1핵심 의미론
메서드의 성질 (RFC 9110 9.2절)
안전은 서버 상태를 바꾸지 않는다는 약속, 멱등은 여러 번 보내도 한 번 보낸 것과 결과가 같다는 약속입니다. 멱등한 요청만 네트워크 오류 시 자동 재시도가 안전합니다.
| 메서드 | 안전 | 멱등 | 캐시 가능 | 요청 본문 | 정의 |
|---|---|---|---|---|---|
GET | 예 | 예 | 예 | 정의된 의미 없음 | 9110 |
HEAD | 예 | 예 | 예 | 정의된 의미 없음 | 9110 |
QUERY | 예 | 예 | 예 (본문이 키) | 있음 | 10008 (2026) |
OPTIONS | 예 | 예 | 아니오 | 가능 | 9110 |
TRACE | 예 | 예 | 아니오 | 금지 | 9110 |
PUT | 아니오 | 예 | 아니오 | 있음 | 9110 |
DELETE | 아니오 | 예 | 아니오 | 정의된 의미 없음 | 9110 |
POST | 아니오 | 아니오 | 조건부* | 있음 | 9110 |
PATCH | 아니오 | 아니오 | 조건부* | 있음 | 5789 |
CONNECT | 아니오 | 아니오 | 아니오 | 정의된 의미 없음 | 9110 |
* 명시적 신선도 정보와 요청 URI와 같은 Content-Location이 있을 때만. 실제로 POST 응답을 캐시하는 구현은 거의 없습니다. DELETE가 멱등인 이유는 두 번째 호출의 응답 코드(404)가 달라도 서버 상태는 같기 때문입니다.
상태 코드 탐색기
자주 헷갈리는 짝
| 상황 | 코드 | 구분 기준 |
|---|---|---|
| 로그인 안 함 vs 권한 없음 | 401 / 403 | 401은 “누구인지 모름”, 반드시 WWW-Authenticate 동반. 403은 “누구인지 알지만 안 됨”. 존재 자체를 숨기려면 404도 허용. |
| 형식 오류 vs 검증 실패 | 400 / 422 | JSON 파싱 불가 등 문법 문제는 400, 문법은 맞지만 값이 규칙 위반(이메일 형식, 재고 부족)이면 422. |
| 상태 충돌 vs 조건 실패 | 409 / 412 | 중복 생성·상태 전이 불가는 409. If-Match 같은 조건부 요청의 조건이 틀렸으면 412. |
| 영구 이동 | 301 / 308 | 301은 POST가 GET으로 바뀔 수 있음. 메서드와 본문을 유지하려면 308. |
| 임시 이동 | 302 / 303 / 307 | 303은 “결과는 GET으로 저기서 보라”(POST 후 리다이렉트). 307은 메서드 유지. 302는 역사적으로 모호. |
| 상위 서버 문제 | 502 / 503 / 504 | 502는 잘못된 응답, 504는 응답 없음(타임아웃), 503은 이 서버 자체가 과부하·점검 중. |
2.2HTTP/2와 HTTP/3
HTTP/1.1은 연결 하나에 요청 하나씩만 처리할 수 있었습니다. HTTP/2는 연결 하나에 여러 스트림을 섞었지만 TCP 손실 시 전부 멈추는 문제가 남았고, HTTP/3는 QUIC으로 그 문제까지 없앴습니다.
| HTTP/1.1 | HTTP/2 | HTTP/3 | |
|---|---|---|---|
| 전송 | TCP | TCP | QUIC (UDP) |
| 형식 | 텍스트 | 바이너리 프레임 | 바이너리 프레임 |
| 다중화 | 없음 (연결 6개 병렬) | 스트림 | 스트림 (독립 전달) |
| HOL 블로킹 | 요청 단위 | TCP 패킷 단위로 남음 | 없음 |
| 헤더 압축 | 없음 | HPACK (7541) | QPACK (9204) |
| 협상 | - | TLS ALPN h2 | Alt-Svc 또는 HTTPS 레코드 h3 |
| 연결 이전 | 불가 | 불가 | Connection ID로 가능 |
2.3URI와 출처
2.4캐싱
캐시는 두 가지만 판단합니다. 저장해도 되는가, 그리고 지금 그대로 써도 되는가(신선한가). 신선하지 않으면 검증(304)하거나 다시 받습니다. 지시자를 바꿔 가며 결과를 확인해 보세요.
Cache-Control 시뮬레이터
RFC 9111 · 5861 · 8246ETag로 동시 수정 막기
RFC 9110 13장 · 6585두 관리자가 같은 상품을 동시에 고칩니다. 조건 없이 저장하면 나중 저장이 앞의 변경을 지워버립니다(lost update). If-Match로 저장하면 서버가 412로 막아줍니다. A와 B 모두 먼저 GET한 뒤 차례로 저장해 보세요.
관리자 A · 가격 +3,000원
관리자 B · 이름에 “ Pro” 추가
서버 · /products/7
2.5메서드와 상태 코드 확장
2026년 6월 발행된 QUERY(10008)는 2010년 PATCH 이후 처음 표준화된 범용 HTTP 메서드입니다.
2.6필드(헤더)
새 헤더를 설계한다면 문자열을 직접 파싱하지 말고 구조화 필드(9651)를 쓰는 것이 현재 IETF의 기본값입니다.
2.7콘텐츠, 압축, 무결성
2.8쿠키와 HSTS
쿠키 명세는 2011년판(6265)이 공식이지만 브라우저는 개정 초안(6265bis)을 기준으로 동작합니다. SameSite, __Host- 접두사는 초안에만 있습니다.
2.9터널과 프록시 (MASQUE)
§ 3
API 설계
API 설계에 관한 RFC는 대부분 “HTTP에 이미 있는 것을 쓰라”고 말합니다. 그 출발점이 BCP 56(RFC 9205)입니다. 아래 표는 실무에서 흔히 보이는 방식과 RFC가 제시하는 방식을 나란히 놓은 것입니다.
| 주제 | 흔히 쓰는 방식 | RFC 기반 방식 |
|---|---|---|
| 오류 응답 | 서비스마다 다른 {"error": ...} | application/problem+json (9457) |
| 부분 수정 | PUT 전체 교체, 임의 형식 PATCH | Merge Patch (7396) 또는 JSON Patch (6902) |
| 동시 수정 | 마지막 저장이 이김 | ETag + If-Match → 412, 필요하면 428로 강제 (9110, 6585) |
| 페이지네이션 | 본문에 offset·page | Link: rel="next" (8288) + 커서 |
| 날짜·시간 | Unix 밀리초 숫자 | RFC 3339 문자열, 시간대 이름은 9557 |
| 식별자 | 자동 증가 정수, UUIDv4 | UUIDv7 (9562) |
| 오래 걸리는 작업 | 200 후 임의 폴링 URL | 202 Accepted + Location, Prefer: respond-async (7240) |
| 요청 한도 | X-RateLimit-* | 429 + Retry-After (6585), RateLimit 필드 (초안) |
| 재시도 안전성 | 클라이언트가 알아서 | Idempotency-Key (초안) |
| 버전 은퇴 | 공지 메일 | Deprecation (9745) + Sunset (8594) → 410 |
| 커스텀 헤더 이름 | X-Request-Id | 접두사 없는 이름 (6648) |
| 복잡한 검색 | POST /search | QUERY (10008). 프레임워크·프록시 지원 확인 후 |
3.1설계 원칙
3.2오류 응답
Problem Details 만들기
RFC 9457title은 유형마다 고정이고, 사람이 읽을 이번 상황 설명은 detail에 씁니다. 클라이언트 로직은 title이나 detail 문자열이 아니라 type URI로 분기해야 합니다.
3.3JSON 계열
JSON Patch와 Merge Patch 비교
RFC 6902 · 7396 · 69013.4링크와 페이지네이션
3.5폐기와 은퇴
3.6데이터 형식
UUIDv7 해부
RFC 95623.7진행 중인 초안
아직 RFC 번호는 없지만 실무에서 이미 널리 쓰이는 관행을 표준화하는 중인 문서들입니다. 필드 형식이 판마다 바뀔 수 있으니 구현 전에 datatracker에서 최신판을 확인하세요.
결제 재시도와 Idempotency-Key
draft-ietf-httpapi-idempotency-key-header결제 요청을 보냈는데 서버는 처리했고 응답만 유실됐다고 합시다. 클라이언트는 성공 여부를 모르니 재시도합니다.
카드 청구 내역
서버의 키 저장소
§ 4
인증과 보안
보안 RFC는 세 층으로 나눠 보면 정리가 쉽습니다. 통로를 지키는 TLS, 상대가 누구인지 보증하는 PKI, 무엇을 해도 되는지 정하는 인가(OAuth). 여기에 토큰 형식(JOSE)과 암호 기초가 받쳐 줍니다.
4.1TLS
TLS 1.3 전체 핸드셰이크
RFC 84464.2인증서와 PKI
브라우저가 자물쇠를 보여주기까지 인증서 체인 검증, 호스트 이름 확인, CT 로그 기록 확인이 함께 일어납니다.
4.3HTTP 인증과 메시지 서명
4.4OAuth 2.0 생태계
OAuth는 RFC 하나가 아니라 30개 가까운 문서의 묶음입니다. 지금 새로 만든다면 기준은 Authorization Code + PKCE 하나이고, 나머지는 필요에 따라 더하는 부품입니다. 브라우저 앱이라면 토큰을 브라우저에 두지 않는 BFF 구조가 최신 권고(10017)입니다.
Authorization Code + PKCE 흐름
RFC 6749 · 7636 · 9207 · 9700첫 단계의 값은 브라우저에서 실제로 계산한 SHA-256입니다.
4.5JOSE와 JWT
JWT 디코더
RFC 7519 · 7515 · 8725 · 9068헤더
페이로드
4.6암호 기초
TOTP 직접 계산
RFC 6238 · 4226 · 4648인증 앱에 등록할 때 QR 코드에 들어 있는 바로 그 값입니다. 예시 키 그대로 써 보고, 실제 계정 키는 넣지 마세요.
4.7계정과 디렉터리
§ 5
부록: RFC가 아닌 웹 표준
웹에서 매일 쓰는 기술 중 상당수는 RFC가 아닙니다. 찾아볼 곳을 잘못 짚지 않도록 정리했습니다.
| 기술 | 표준 기관 | RFC와의 관계 |
|---|---|---|
| CORS, Fetch, URL, HTML, Streams | WHATWG (Living Standard) | 출처 개념은 RFC 6454, URL 문법은 3986과 다른 부분이 있음 |
| CSP, WebAuthn, Service Worker, Permissions Policy | W3C | CSP frame-ancestors가 X-Frame-Options(7034) 대체 |
| OpenID Connect | OpenID Foundation | OAuth 2.0(6749)과 JWT(7519) 위에 인증 계층 |
| FIDO2 / CTAP, 패스키 | FIDO Alliance + W3C | CBOR(8949), COSE(9052) 사용 |
| OpenAPI | OpenAPI Initiative | api-catalog(9727)로 문서 위치 공개 가능 |
| JSON Schema | json-schema.org | IETF 초안으로 시작했으나 독립 |
| GraphQL | GraphQL Foundation | HTTP 위에서 쓰는 방식은 별도 명세(GraphQL over HTTP) |
| gRPC | 프로젝트 자체 명세 | HTTP/2(9113) 위에서 동작, 트레일러 활용 |
| BBR 혼잡 제어 | IETF 초안 (CCWG) | 아직 RFC 아님 |
| Semantic Versioning | semver.org | 표준 기관 문서 아님 |
| ECMAScript, JSON의 JS 구문 | Ecma TC39 | JSON 교환 형식은 RFC 8259와 ECMA-404가 같은 내용 |
| TCP/IP 아래 링크 계층 | IEEE 802 (이더넷, Wi-Fi) | IP를 그 위에 싣는 방법만 RFC |
§ 6
전체 색인
이 교과서에 실린 모든 문서입니다. 번호를 누르면 해당 설명으로 이동합니다. “학습 완료” 표시는 이 브라우저에만 저장됩니다.
| 번호 | 제목 | 영역 | 상태 | 연도 | ✓ |
|---|