🌐 HTTP Protocol — Deep Dive: Message Structure, Status Codes, Headers, Caching, HTTP/2, HTTP/3

Panduan komprehensif Hypertext Transfer Protocol dari wire format sampai modern HTTP/3. Mencakup message structure (request/response), status codes 1xx–5xx beserta semantics, headers (general, request, response, entity), caching mechanisms (ETag, Cache-Control, Vary), connection management (Keep-Alive, pipelining, multiplexing), content negotiation, HTTP/2 frames & HPACK compression, HTTP/3 QUIC fundamentals, dan attack surface di setiap layer HTTP. Nota ini adalah fondasi untuk semua catatan web security, API security, dan WAF di vault — karena tanpa paham HTTP, lo cuma pake tool buta.

Posisi di Vault

Ini adalah fondasi layer 7 untuk semua catatan security yang bergantung pada HTTP. Baca ini dulu sebelum web-hacking-exploitation (eksploitasi web), api-security-deep-dive (API security), waf-reverse-proxy-deepdive (WAF & reverse proxy), cobalt-strike dan sliver (C2 HTTP profiles), cloudflare-ruleset-engine-phases (Cloudflare WAF rules), serta api-protocols-deepdive (perbandingan protokol API). networking-fundamentals-tcpip-bgp adalah prasyarat layer 4 (TCP).


Daftar Isi


Foundation — Arsitektur HTTP

Model Client-Server

┌──────────┐   Request (method, URI, headers, body)    ┌──────────┐
│  Client  │ ────────────────────────────────────────→  │  Server  │
│ (Browser │ ←──────────────────────────────────────── │ (nginx)  │
│  / curl) │          Response (status, headers, body)  │          │
└──────────┘                                           └──────────┘

HTTP adalah stateless protocol — server tidak menyimpan state client antar request. State dikelola di layer lain: cookies, session tokens, JWT.

Karakteristik Dasar

PropertiHTTP/1.0HTTP/1.1HTTP/2HTTP/3
RFC1945 (1996)2616 → 7230-35 (1999 → 2014)7540 (2015)9114 (2022)
KoneksiSatu request per koneksiKeep-Alive defaultMultiplexed streamQUIC (UDP-based)
HeaderPlaintextPlaintextHPACK compressedQPACK compressed
PrioritasStream priorityStream priority
Server Push✅ (deprecated!)
TransportTCPTCPTCPQUIC (UDP)

Uniform Resource Identifier (URI)

  ┌──────────────────┐ ┌──────┐ ┌────────┐ ┌──────┐ ┌──────────┐
  https://user:pass@api.example.com:8443/path/to/res?query=val#frag
  └─┬──┘ └──┬──┘└───┬────┘ └─┬─┘ └────┬────┘ └───┬───┘
  Scheme    User    Host      Port     Path      Query
KomponenContohKeterangan
Schemehttps, http, ftpProtokol. HTTPS = HTTP over TLS
User Infouser:pass@Deprecated. Jangan dipake — kredensial di URL adalah security risk
Hostapi.example.comDomain atau IP. Wajib di HTTP/1.1 via Host header
Port:8443Default: 80 (HTTP), 443 (HTTPS)
Path/path/to/resHierarki resource. Bisa di-encode (URL encoding)
Query?query=valKey-value pairs. ? separator, & antar pair, = antara key & value
Fragment#fragTidak dikirim ke server — hanya client-side (browser scroll)

Message Structure — Request & Response

HTTP Request

METHOD /path HTTP/version\r\n
Header1: value\r\n
Header2: value\r\n
\r\n
body

Contoh konkret:

GET /api/users?page=1 HTTP/1.1\r\n
Host: api.example.com\r\n
User-Agent: curl/8.0\r\n
Accept: application/json\r\n
Authorization: Bearer eyJhbGci...\r\n
\r\n

HTTP Response

HTTP/version status_code reason_phrase\r\n
Header1: value\r\n
Header2: value\r\n
\r\n
body

Contoh konkret:

HTTP/1.1 200 OK\r\n
Content-Type: application/json\r\n
Content-Length: 42\r\n
Cache-Control: max-age=3600\r\n
\r\n
{"users":[],"page":1,"total_pages":0}

Transfer Modes

ModeCara Kirim BodyKelebihanKekurangan
Content-LengthHeader Content-Length: N — server baca N bytesSederhana, compatible semua versiWajib tahu panjang sebelum kirim — gak cocok buat streaming
Chunked TransferHeader Transfer-Encoding: chunked — body dipecah jadi chunk, tiap chunk dikirim dengan ukuran sendiriBisa streaming tanpa tahu panjang totalOverhead per chunk, tidak di HTTP/2 (pakai DATA frame)
MultipartContent-Type: multipart/form-data; boundary=---Kirim file + field dalam satu bodyParsing lebih kompleks

Status Codes

1xx — Informational

CodeNameMaknaPenggunaan
100ContinueServer udah terima headers, client boleh kirim bodyBiar gak kirim body besar cuma buat ditolak
101Switching ProtocolsServer setuju upgrade protokol (WebSocket, HTTP/2 upgrade)WebSocket handshake, HTTP/2 Upgrade header
102Processing (WebDAV)Server masih proses, jangan timeoutWebDAV long operations — jarang dipake
103Early HintsServer kirim hints sebelum response final (Link header buat preload)HTTP/2 dan HTTP/3 — optimasi loading

2xx — Success

CodeNameMaknaKapan Pake
200OKRequest berhasil, body berisi resourceGET berhasil, POST sukses
201CreatedResource baru berhasil dibuatPOST ke /users → user baru
202AcceptedRequest diterima tapi belum diproses (async)Job queue, background task
204No ContentBerhasil tapi gak ada body yang dikirimDELETE sukses, PUT update tanpa balikan
206Partial ContentHanya sebagaian resource dikirim (Range header)Video streaming, download resume

3xx — Redirection

CodeNameMaknaKapan Pake
301Moved PermanentlyURL udah pindah permanen — browser ganti bookmarkDomain migration, HTTP→HTTPS redirect
302FoundURL pindah sementara — jangan ganti bookmarkPost/Redirect/Get pattern, login redirect
303See OtherRedirect ke URL lain, method HARUS jadi GETForm submission redirect
304Not ModifiedResource gak berubah — pake cacheConditional request (If-None-Match, If-Modified-Since)
307Temporary RedirectSama kayak 302 tapi method & body TIDAK BOLEH diubahPATCH redirect
308Permanent RedirectSama kayak 301 tapi method & body TIDAK BOLEH diubahAPI permanent migration

⚠️ 301 vs 302 vs 307 vs 308:

  • 301/302 — browser BOLEH ganti POST → GET (banyak implementasi broken)
  • 307/308 — method & body WAJIB dipertahankan. Pake ini buat API redirect!

4xx — Client Error

CodeNameMaknaKapan Pake
400Bad RequestServer gak paham request — format salahValidation error, malformed JSON
401UnauthorizedBelum login / token gak validMissing/Wrong Authorization header
403ForbiddenUdah login tapi gak punya aksesRBAC deny, IP block, geo-restriction
404Not FoundResource gak adaEndpoint salah, resource dihapus
405Method Not AllowedMethod gak diizinkan untuk endpoint iniPOST ke endpoint yang cuma terima GET
406Not AcceptableServer gak bisa kasih format yang client minta (Accept header)Client minta application/xml tapi server cuma punya JSON
408Request TimeoutClient terlalu lama kirim dataTimeout konfigurasi server
409ConflictState resource bentrok dengan requestConcurrent edit, duplicate entry
410GoneResource udah dihapus permanen (beda sama 404)API deprecation
413Content Too LargeBody melebihi batas serverUpload file terlalu gede
415Unsupported Media TypeContent-Type gak didukungKirim XML ke endpoint yang cuma terima JSON
422Unprocessable EntityBody format bener tapi isinya salahValidasi semantik (WebDAV, REST API umum)
429Too Many RequestsRate limit exceededAPI Gateway rate limiting
431Request Header Fields Too LargeHeader kegedeanCookie overflow attack

5xx — Server Error

CodeNameMaknaKapan Pake
500Internal Server ErrorServer error generic — jangan kasih detail ke clientCatch-all server error
501Not ImplementedMethod belum didukung serverFitur belum dibuat
502Bad GatewayUpstream server balikin response invalidProxy/gateway error dari backend
503Service UnavailableServer sementara gak bisaMaintenance, overload, rate limiting di level server
504Gateway TimeoutUpstream server gak balik tepat waktuBackend slow, database timeout

Best Practice Status Codes

  • Response error WAJIB sertakan body deskriptif + error code spesifik untuk debugging
  • Jangan expose stack trace di 500 error — security risk
  • 422 lebih tepat untuk validation error daripada 400

Headers — General, Request, Response, Entity

General Headers (berlaku untuk request & response)

HeaderContohFungsi
DateDate: Wed, 15 Jul 2026 10:00:00 GMTTimestamp server — wajib di response
ConnectionConnection: keep-alive (default HTTP/1.1)Kontrol koneksi: keep-alive vs close
Cache-ControlCache-Control: no-cacheDirective caching (detail di section caching)
Transfer-EncodingTransfer-Encoding: chunkedEncoding transfer — bukan content encoding

Request Headers

KategoriHeaderContohFungsi
IdentityHostHost: api.example.comWAJIB di HTTP/1.1 — nama server virtual
AuthAuthorizationAuthorization: Bearer eyJhbG...Credential / token — Basic, Bearer, Digest
AuthProxy-AuthorizationSama formatAuth ke proxy
ClientUser-AgentUser-Agent: curl/8.0.0Identitas client — sering dipalsukan oleh bot/C2
ClientRefererReferer: https://site.com/pageHalaman asal — privacy risk (bocorin URL)
ClientFromFrom: user@example.comEmail — jarang dipake
ContentContent-TypeContent-Type: application/jsonTipe body — WAJIB kalo ada body
ContentContent-LengthContent-Length: 42Ukuran body dalam bytes
ContentContent-EncodingContent-Encoding: gzipKompresi yang dipake di body
NegotiationAcceptAccept: application/json, text/plainFormat response yang diterima client
NegotiationAccept-EncodingAccept-Encoding: gzip, deflate, brKompresi yang didukung
NegotiationAccept-LanguageAccept-Language: id, en;q=0.9Bahasa preferensi
NegotiationAccept-Charset(deprecated)Charset — jarang dipake modern
ConditionalIf-Modified-SinceIf-Modified-Since: Wed, 15 Jul 2026 10:00:00 GMTConditional GET — cache validation
ConditionalIf-None-MatchIf-None-Match: "abc123"ETag matching — cache validation
ConditionalIf-MatchIf-Match: "abc123"Untuk optimistic concurrency (PUT)
ConditionalIf-Unmodified-SinceTimestampSame — update cuma kalo gak diubah sejak
RangeRangeRange: bytes=100-199Partial request
CORSOriginOrigin: https://site.comAsal request — basis CORS
CORSAccess-Control-Request-MethodOPTIONSPreflight — method yang diminta
CORSAccess-Control-Request-HeadersX-CustomPreflight — custom headers
SecurityCookieCookie: session=abc; theme=darkSession cookie — detail di section cookies
SecurityDNTDNT: 1Do Not Track — tidak diwajibkan browser implement
CachePragmaPragma: no-cacheHTTP/1.0 backward compatibility — pake Cache-Control aja
CacheExpectExpect: 100-continueClient nunggu 100 Continue sebelum kirim body besar

Response Headers

KategoriHeaderContohFungsi
IdentityServerServer: nginx/1.24Identitas server — bisa disembunyikan
AuthWWW-AuthenticateWWW-Authenticate: Bearer realm="api"Tantangan auth — dikirim bareng 401
AuthProxy-AuthenticateSama formatTantangan proxy auth
CORSAccess-Control-Allow-OriginAccess-Control-Allow-Origin: *Origin yang diizinkan
CORSAccess-Control-Allow-MethodsGET, POST, PUT, DELETEMethod yang diizinkan
CORSAccess-Control-Allow-HeadersContent-Type, AuthorizationHeaders yang diizinkan
CORSAccess-Control-Allow-CredentialstrueApakah kredensial boleh dikirim cross-origin
CORSAccess-Control-Max-Age86400Cache preflight response (detik)
CORSAccess-Control-Expose-HeadersX-RateLimit-*Header non-standar yang boleh dibaca JS
SecurityStrict-Transport-SecurityStrict-Transport-Security: max-age=31536000; includeSubDomainsHSTS — paksa HTTPS
SecurityContent-Security-PolicyContent-Security-Policy: default-src 'self'CSP — cegah XSS
SecurityX-Content-Type-OptionsX-Content-Type-Options: nosniffCegah MIME sniffing
SecurityX-Frame-OptionsX-Frame-Options: DENYCegah clickjacking
SecurityX-XSS-ProtectionX-XSS-Protection: 1; mode=blockLegacy — browser modern gak pake
SecurityReferrer-PolicyReferrer-Policy: strict-origin-when-cross-originKontrol isi Referer header
SecurityPermissions-PolicyPermissions-Policy: camera=(), microphone=()Kontrol API browser
SecuritySet-CookieSet-Cookie: session=abc; HttpOnly; Secure; SameSite=LaxSet cookie — detail di section cookies
LocationLocationLocation: https://new-url.comRedirect target — bareng 3xx
RetryRetry-AfterRetry-After: 120Kapan client boleh coba lagi — bareng 429/503
CacheAgeAge: 3600Umur cache hit di proxy
InfoWarning(deprecated)Informasi tambahan
TimingTiming-Allow-OriginTiming-Allow-Origin: *Resource Timing API access

Entity Headers (tentang body)

HeaderContohFungsi
Content-TypeContent-Type: application/json; charset=utf-8Tipe media + encoding
Content-LengthContent-Length: 128Ukuran dalam bytes
Content-EncodingContent-Encoding: gzipKompresi (diterapkan setelah Content-Type)
Content-LanguageContent-Language: idBahasa konten
Content-LocationContent-Location: /api/users?page=1URL alternatif resource ini
Content-DispositionContent-Disposition: attachment; filename="report.pdf"Kontrol cara browser nampilin konten
Content-RangeContent-Range: bytes 100-199/1000Posisi partial response
ETagETag: "abc123"Identifier unik versi resource — untuk cache
Last-ModifiedLast-Modified: Wed, 15 Jul 2026 10:00:00 GMTTimestamp update terakhir
ExpiresExpires: Thu, 16 Jul 2026 10:00:00 GMTWaktu kadaluarsa — HTTP/1.0

Content Negotiation

Proses client & server negotiate format terbaik untuk resource yang sama.

Server-Driven (Paling Umum)

Client kirim Accept headers → server pilih format terbaik:

GET /api/users HTTP/1.1
Accept: application/json;q=0.9, application/xml;q=0.5, text/html;q=0.1
  • q = quality value (prioritas 0–1). Default: q=1.0
  • Server pilih format dengan q tertinggi yang didukung
  • Kalau gak ada yang cocok → 406 Not Acceptable

Agent-Driven (Jarang)

Server balikin 300 Multiple Choices dengan daftar format → client pilih.

Proactive Content Negotiation in HTTP/2 & HTTP/3

Sama konsepnya — header yang sama dipake di frame headers.


Caching

Caching adalah mekanisme HTTP yang paling sering salah konfigurasi dan menyebabkan security issue.

Freshness Model

Resource dibuat              Cache expires
    │                             │
    ├──────── FRESH ──────────────┤──── STALE ────→
    │                             │
    │←────── Cache HIT ──────────→│
                                  │←── Cache MISS (revalidate) ──→

Cache-Control Directives

DirectiveContohFungsi
max-age=Nmax-age=3600Resource fresh selama N detik setelah server generate
s-maxage=Ns-maxage=3600Sama, tapi khusus shared cache (CDN, proxy) — override max-age
no-cacheno-cacheJangan pake cache tanpa revalidate — masih boleh store, tapi musti tanya server dulu
no-storeno-storeJangan simpan sama sekali — buat data sensitif (banking, token)
must-revalidatemust-revalidateBegitu stale, WAJIB revalidate — gak boleh kirim stale
proxy-revalidateSamaSama tapi khusus shared cache
privateprivate, max-age=3600Cuma browser client yang boleh cache — proxy jangan
publicpublic, max-age=3600Boleh di-cache siapa aja (CDN, proxy, browser)
immutableimmutableResource gak akan berubah selama max-age — browser gak usah revalidate (static assets)
stale-while-revalidatestale-while-revalidate=86400Boleh kirim stale sambil fetch ulang di background
stale-if-errorstale-if-error=86400Kalo server error, kirim stale aja daripada error

ETag & Conditional Request

ETag = identifier unik versi resource (hash, timestamp, atau version number):

# Response
HTTP/1.1 200 OK
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
 
# Request berikutnya (If-None-Match)
GET /resource HTTP/1.1
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
 
# Response kalo gak berubah
HTTP/1.1 304 Not Modified
# (no body — pake cache)

Last-Modified + If-Modified-Since:

Response: Last-Modified: Wed, 15 Jul 2026 10:00:00 GMT
Request:  If-Modified-Since: Wed, 15 Jul 2026 10:00:00 GMT
Response: 304 Not Modified  # atau 200 dengan resource baru

Prioritas: ETag lebih akurat daripada Last-Modified (bisa deteksi perubahan dalam <1 detik).

Caching Security Issues

IssuePenyebabDampak
Sensitive data di cacheResponse dengan data pribadi gak pake no-storeData pasien, token, API key bocor dari cache
Cache poisoningAttacker inject response malicious → cache → semua user dapet response jahatXSS massal, redirect ke phishing
Cache key confusionHeader Vary gak lengkap → dua user dapet response yang sama padahal bedaData bocor antar user
Web Cache DeceptionAttacker trick app untuk cache response sensitif dengan tambahin .css di URLData sensitif jadi public di CDN

Connection Management

HTTP/1.1 menggunakan persistent connections (Keep-Alive) secara default.

HTTP/1.1 Keep-Alive

Connection: keep-alive  # default, bisa explicit
# atau
Connection: close       # Server: "setelah ini, tutup"

Cara kerja:

Client: [ SYN → SYN-ACK → ACK ]
Client: [ Request 1 → Response 1 ]  ← dalam satu koneksi TCP
Client: [ Request 2 → Response 2 ]  ← koneksi yang sama
Client: [ Request 3 → Response 3 ]
Client: [ FIN → ... ]               ← tutup koneksi

Tanpa Keep-Alive (HTTP/1.0), tiap request buka koneksi baru → 3-way handshake + slow start TCP = lambat.

Pipelining (Deprecated)

Kirim banyak request tanpa nunggu response. Bermasalah karena HOL blocking (satu response lambat nahan semua response di belakangnya) dan implementasi proxy yang broken.

HTTP/2 Multiplexing (Solusi HOL Blocking)

Lihat section HTTP/2.

Timeouts & Limits

ParameterDefault (nginx)Fungsi
keepalive_timeout65sBerapa lama koneksi idle boleh hidup
keepalive_requests1000Maks request per koneksi (cegah memory leak)
client_body_timeout60sTimeout baca body client
client_header_timeout60sTimeout baca header client
send_timeout60sTimeout kirim response ke client

Cookies & Session Management

Set-Cookie: sessionId=abc123; Domain=.example.com; Path=/; Max-Age=86400; HttpOnly; Secure; SameSite=Lax
AttributeFungsiSecurity Implication
Domain=.example.comCookie dikirim ke domain & subdomainTerlalu lebar = subdomain yang compromised bisa baca cookie
Path=/Cookie dikirim untuk path ini & sub-pathPath=/admin lebih ketat dari /
Max-Age=NCookie hidup N detik. Max-Age=0 = hapusCookie tanpa expiry = session cookie (hapus saat browser tutup)
Expires=dateSama, HTTP/1.0 style
HttpOnlyJavaScript gak bisa baca cookie via document.cookieWAJIB untuk session cookie — cegah XSS cookie theft
SecureCookie cuma dikirim via HTTPSWAJIB — cegah泄露 di HTTP plaintext
SameSiteKontrol pengiriman cookie cross-site: Strict, Lax, NoneCegah CSRF. Lax = default modern browser. None = butuh Secure

SameSite Explained

ValueLink (click)Form POST dari site lainFetch/XHR cross-siteIframe
Strict❌ No cookie❌ No cookie❌ No cookie❌ No cookie
Lax (default)✅ Send❌ No cookie❌ No cookie❌ No cookie
None✅ Send✅ Send✅ Send✅ Send

Lax adalah kompromi keamanan vs usability — ngirim cookie waktu navigasi GET normal (link), tapi gak ngirim buat POST/background request.


CORS

Cara Kerja

  1. Browser deteksi request cross-origin (beda scheme, host, atau port)
  2. Kalo request sederhana (GET, POST with form content-type) → kirim Origin header
  3. Kalo request kompleks (PUT, DELETE, custom header, non-form content-type) → kirim preflight OPTIONS dulu
  4. Server balikin Access-Control-Allow-* headers
  5. Browser cek: kalo gak cocok → block (JS error), kalo cocok → izinkan

Simple Request vs Preflight

Simple Request: Method = GET/HEAD/POST, Content-Type = application/x-www-form-urlencoded atau multipart/form-data atau text/plain, gak ada custom headers → langsung kirim request, gak perlu preflight.

Preflight Request:

OPTIONS /api/resource HTTP/1.1
Origin: https://malicious-site.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header

Preflight Response:

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://trusted-site.com
Access-Control-Allow-Methods: PUT, POST, GET
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 86400

Common Mistakes

MistakeDampak
Access-Control-Allow-Origin: * dengan credentials: trueInvalid — browser block. Kalo pake credentials, origin WAJIB spesifik
Access-Control-Allow-Origin: nullOrigin null bisa dari sandbox iframe — bikin CORS bypass
Reflecting origin tanpa validasiAttacker bisa pake Origin: https://evil.com → server balikin Access-Control-Allow-Origin: https://evil.com → browser izinin akses
Gak validasi preflightAttacker bisa abuse OPTIONS untuk bypass auth

HTTP/2

Binary Framing Layer

HTTP/2 mengubah HTTP dari textual (baca: ASCII) ke binary — bukan perubahan format biasa, ini fundamental redesign:

HTTP/1.1:
  GET /resource HTTP/1.1
  Host: server.com
  → di-parse line by line sebagai ASCII text

HTTP/2:
  HEADERS frame (stream 1):
    :method: GET
    :path: /resource
    :authority: server.com
  → binary, pre-parsed, dikirim dalam frame

Frame Types

Frame TypeFungsi
HEADERSHeader HTTP (request atau response)
DATABody
SETTINGSParameter koneksi (konfigurasi peer)
PRIORITYPrioritas stream
RST_STREAMBatalkan stream (tidak perlu tutup koneksi)
GOAWAYInisiasi shutdown koneksi
PINGKeep-alive + RTT measurement
WINDOW_UPDATEFlow control — update window size

Streams, Messages, Frames

┌──────────────────────────────────────────┐
│          1 TCP Connection                │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  │
│  │ Stream 1│  │ Stream 3│  │ Stream 5│  │
│  │ GET /a  │  │ POST /b │  │ GET /c  │  │
│  │ (HEADERS)│  │(HEADERS)│  │ (HEADERS)│  │
│  └─────────┘  │ (DATA)  │  └─────────┘  │
│               └─────────┘               │
└──────────────────────────────────────────┘

HPACK — Header Compression

Tanpa kompresi, header HTTP bisa 400-800 bytes per request. HPACK kompres jadi ~30 bytes:

Index Table (static — 61 entries predefined):
+-------+-----------------------+
| Index | Header Name & Value   |
+-------+-----------------------+
| 2     | :method: GET          |
| 3     | :method: POST         |
| 5     | :path: /index.html    |
| 7     | :authority:           |
| ...   | ...                   |
+-------+-----------------------+

Index Table (dynamic — built during session):
Makin banyak request → makin banyak entry di-cache
→ makin kecil ukuran header

Server Push (Deprecated)

Chrome 106+ (Sept 2022) menghapus HTTP/2 Server Push karena adopsi rendah dan masalah performa. Gantinya: 103 Early Hints dan preload links.

HOL Blocking in HTTP/2?

TCP-level HOL blocking tetap ada: kalo 1 packet TCP hilang, semua stream nunggu retransmit. Ini yang diperbaiki HTTP/3 dengan pindah ke QUIC (UDP).


HTTP/3 — QUIC

HTTP/3 adalah HTTP over QUIC (Quick UDP Internet Connections), bukan TCP.

Key Differences

AspekHTTP/2 (TCP)HTTP/3 (QUIC)
TransportTCPQUIC (UDP)
HandshakeTCP (1 RTT) + TLS (1 RTT) = 2 RTTQUIC (0-RTT atau 1-RTT)
HOL blockingYa (TCP packet loss → semua stream nunggu)Tidak (setiap stream independent)
Connection migrationTidak (putus kalo pindah jaringan)Ya (connection ID — pindah WiFi tanpa putus)
EncryptionOpsional (HTTPS via TLS)Wajib (built-in)
Implementationnginx, h2o, CaddyCloudflare, Google, nginx (experimental)

QUIC Connection Establishment

Client                                          Server
  │                                                │
  │───── QUIC Initial (ClientHello + data) ───────→│  0-RTT (kalo pernah connect sebelumnya)
  │←─── QUIC Handshake (ServerHello + data) ───────│
  │←─── QUIC Initial (done) ───────────────────────│
  │←═══════════ Data ══════════════════════════════→│  1-RTT total vs 2-3 RTT TCP+TLS

Connection Migration

Client di WiFi:
  [Connection ID: CID-ABC] → Server

Client pindah ke 4G:
  [Connection ID: CID-ABC] (IP baru!) → Server
  Server kenali dari CID → lanjut tanpa handshake ulang

Ini penting buat mobile: pindah WiFi ↔ 4G tanpa putus streaming atau download.


Attack Surface

HTTP Request Smuggling

Eksploitasi perbedaan parsing Content-Length vs Transfer-Encoding antara frontend (proxy/CDN) dan backend:

POST / HTTP/1.1
Host: vulnerable-server.com
Content-Length: 13
Transfer-Encoding: chunked
 
0
 
GET /admin HTTP/1.1
Host: internal-admin.com

Frontend parse Transfer-Encoding: chunked → baca 0\r\n sebagai end of message. Backend parse Content-Length: 13 → baca 13 bytes → GET /admin... adalah request berikutnya dalam koneksi yang sama.

Cache Poisoning

Attacker inject response dengan header X-Forwarded-Host: evil.com → server generate redirect ke evil.com → CDN cache → semua user kena redirect.

HTTP Parameter Pollution (HPP)

GET /search?q=term&q=malicious HTTP/1.1

Backend beda-beda parse priority: nginx = pertama, Python = terakhir, PHP = terakhir. Bisa bypass validation.

Host Header Attack

GET / HTTP/1.1
Host: evil.com

Kalo aplikasi pake Host header buat generate link (password reset, redirect), attacker bisa bikin link phishing.

CRLF Injection

GET /%0d%0aSet-Cookie:%20session=evil HTTP/1.1

Newline yang di-encode → server inject header. Modern framework sudah prevent ini.

Insecure Methods

MethodRisk
TRACECross-Site Tracing (XST) — bocorin cookie via headers
PUTUpload file → RCE
DELETEHapus resource
OPTIONSInfo metode yang didukung — informasi recon

Mitigasi: Disable TRACE, PUT, DELETE untuk public endpoint.

HTTP/2 Rapid Reset Attack (CVE-2023-44487)

Attack 2023 yang memanfaatkan fitur HTTP/2 RST_STREAM:

  • Kirim banyak request → langsung cancel stream
  • Server alloc resource per stream → client cancel terus → resource exhaustion
  • Dampak: DDoS record 398M rps via Cloudflare
  • Mitigasi: Rate limit stream creation + cancel per koneksi

Practical Tooling

cURL — HTTP Debugging

# Lihat full request-response
curl -v https://api.example.com
 
# Cuma headers
curl -I https://example.com
 
# Custom method + body
curl -X PUT -H "Content-Type: application/json" -d '{"key":"val"}' https://api.example.com/resource
 
# With cookie
curl -b "session=abc" https://api.example.com
 
# Follow redirects
curl -L http://example.com
 
# HTTP/2
curl --http2 https://http2.example.com
 
# HTTP/3
curl --http3 https://http3.example.com
 
# Measure timing
curl -w "\nTime: %{time_total}s\nHTTP: %{http_version}\n" -o /dev/null -s https://example.com

Python http.client — Wire Level

import http.client
 
conn = http.client.HTTPConnection("example.com", 80)
conn.request("GET", "/", headers={"Host": "example.com"})
resp = conn.getresponse()
print(resp.status, resp.reason)
print(resp.headers)
print(resp.read().decode())
conn.close()

HTTP/2 Frame Inspector (nghttp2)

# Install
apt install nghttp2-client
 
# Lihat HTTP/2 frames
nghttp -v https://nghttp2.org
 
# Output:
# [  0.000] send HEADERS frame <stream=1>
#           ; END_STREAM | END_HEADERS
#           (:method: GET)
#           (:path: /)
#           (:scheme: https)
#           (:authority: nghttp2.org)
# [  0.068] recv SETTINGS frame <stream=0>
# [  0.068] recv HEADERS frame <stream=1>
#           ; END_HEADERS
#           (:status: 200)
#           (server: nghttp2)

Checklist

☐ Paham HTTP message structure (request line, headers, body)
☐ Hafal status codes: 2xx (success), 3xx (redirect), 4xx (client error), 5xx (server error)
☐ Bisa bedain 301 vs 302 vs 307 vs 308 — mana yang boleh ganti method
☐ Paham Content-Type vs Content-Encoding (apa isi vs bagaimana dikirim)
☐ Cache-Control: tau beda no-cache (store tapi revalidate) vs no-store (jangan simpan)
☐ Paham ETag + conditional request (If-None-Match, If-Match)
☐ Bisa baca tcpdump HTTP traffic dan kenali handshake + transfer
☐ Cookie: HttpOnly, Secure, SameSite — wajib paham fungsinya
☐ CORS: kenapa preflight, cara kerja origin check, common mistakes
☐ HTTP/2: binary framing, multiplexing, HPACK
☐ HTTP/3: QUIC, 0-RTT, connection migration
☐ Attack surface: request smuggling, cache poisoning, host header, CRLF injection

Koneksi ke Vault


References

  1. IETF. RFC 9110: HTTP Semantics. 2022. https://httpwg.org/specs/rfc9110.html
  2. IETF. RFC 9111: HTTP Caching. 2022. https://httpwg.org/specs/rfc9111.html
  3. IETF. RFC 9112: HTTP/1.1. 2022. https://httpwg.org/specs/rfc9112.html
  4. IETF. RFC 9113: HTTP/2. 2022. https://httpwg.org/specs/rfc9113.html
  5. IETF. RFC 9114: HTTP/3. 2022. https://httpwg.org/specs/rfc9114.html
  6. IETF. RFC 7541: HPACK: Header Compression for HTTP/2. 2015.
  7. IETF. RFC 6265: HTTP State Management Mechanism (Cookies). 2011.
  8. IETF. RFC 6454: The Web Origin Concept. 2011.
  9. WHATWG. Fetch Standard (CORS). https://fetch.spec.whatwg.org/
  10. Mozilla MDN. HTTP Documentation. https://developer.mozilla.org/en-US/docs/Web/HTTP
  11. Mozilla MDN. CORS. https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
  12. Mozilla MDN. HTTP Caching. https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching
  13. PortSwigger. HTTP Request Smuggling. https://portswigger.net/web-security/request-smuggling
  14. PortSwigger. Web Cache Poisoning. https://portswigger.net/web-security/web-cache-poisoning
  15. PortSwigger. HTTP Parameter Pollution. https://portswigger.net/kb/issues/00100400_http-parameter-pollution
  16. nginx. NGINX HTTP Configuration. https://nginx.org/en/docs/http/ngx_http_core_module.html
  17. Cloudflare. HTTP/2 Rapid Reset Attack. https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/
  18. Google. QUIC Protocol. https://quicwg.org/
  19. curl. curl man page. https://curl.se/docs/manpage.html
  20. httpbin.org. HTTP Request & Response Service. https://httpbin.org/

Bottom Line

HTTP adalah bahasa internet — setiap request, response, header, dan status code punya makna spesifik yang bisa dieksploitasi atau dilindungi. Tanpa paham HTTP secara fundamental, lo cuma bisa pake tool (Burp, curl, WAF) secara buta — gak bisa bedain mana yang normal, mana yang attack. Fokus utama buat security engineer: (1) Cache semantics — misconfigured cache adalah sumber data breach paling umum. (2) CORS — origin validation yang salah = jalan buat CSRF dan data exfil. (3) Connection management — smuggled request bisa bypass WAF. (4) HTTP/2 Rapid Reset — bukti bahwa bahkan protokol modern punya attack surface baru. Status code 304? Itu bukan cuma “not modified” — itu cache oracle buat attacker.