Frontend Labs
⋯

Part 8 — Layer 6: Presentation

Job

Make sure both sides agree on what the bytes mean: character encoding, data serialisation, compression, and encryption.

In our story

Four presentation transformations happen to your order before it hits the wire:

JS object { cartId: "c_8812", paymentMethodId: "pm_77" }
   │  1. SERIALISE   JSON.stringify → text
   ▼
'{"cartId":"c_8812","paymentMethodId":"pm_77"}'
   │  2. ENCODE      text → UTF-8 bytes (43 bytes)
   ▼
7b 22 63 61 72 74 49 64 22 3a 22 63 5f 38 38 31 32 22 ...
   │  3. COMPRESS    headers compressed with HPACK (HTTP/2); body too small to gzip
   ▼
   │  4. ENCRYPT     TLS 1.3 record: AES-128-GCM with this session's keys
   ▼
17 03 03 00 5a  <90 bytes of ciphertext + 16-byte authentication tag>

On the server, the ALB decrypts (TLS terminates there). It then either re-encrypts towards the pod (end-to-end TLS) or sends plaintext inside the VPC. Finally the pod's framework decompresses, decodes, and deserialises the bytes back into an object.

How it works

1. The TLS 1.3 handshake (when there's no warm connection to reuse):

Client                                                       Server (ALB)
  │── ClientHello ───────────────────────────────────────────────▶│
  │     supported versions: TLS 1.3                               │
  │     cipher suites: TLS_AES_128_GCM_SHA256, CHACHA20_POLY1305  │
  │     key_share: X25519 public key        ← key exchange starts NOW
  │     SNI: shop.example.com               ← which certificate do I want (plaintext!)
  │     ALPN: h2, http/1.1                  ← which L7 protocol next
  │                                                               │
  │◀── ServerHello (key_share) ───────────────────────────────────│
  │◀── {EncryptedExtensions, Certificate, CertificateVerify, ──── │   ← already encrypted
  │     Finished}                                                 │
  │                                                               │
  │── {Finished} ── {HTTP request} ──────────────────────────────▶│   1 RTT total

The four things TLS gives you:

Property Mechanism
Confidentiality Symmetric encryption (AES-GCM / ChaCha20) with keys from an ephemeral ECDHE exchange (X25519)
Integrity AEAD authentication tag on every record. Any tampering → connection fails
Authentication Certificate chain: shop.example.com → intermediate CA → a root CA in your OS/browser trust store; server proves it owns the private key (CertificateVerify)
Forward secrecy Ephemeral keys: stealing the server's private key later doesn't decrypt recorded past traffic

TLS 1.2 needed 2 RTTs. TLS 1.3 needs 1. QUIC combines the transport and TLS handshakes into 1 as well.

What's still visible on the wire: the destination IP, the port, SNI (the hostname, unless Encrypted Client Hello is used), packet sizes, and timing. Encryption hides content, not metadata.

2. Serialisation formats.

Format Strengths Gotchas
JSON Human-readable, universal No integer type: JS loses precision above 2⁵³−1, so send 64-bit IDs as strings. No binary, no dates (agree on ISO-8601), verbose
Protobuf / gRPC Compact, typed, schema evolution Needs schema discipline: never reuse field numbers; not human-readable
Avro / Parquet Schema registry, analytics Writer and reader schema compatibility rules
XML / SOAP Mature validation Heavy; XXE attacks if parsers are misconfigured

3. Character encoding. Always UTF-8 on the wire. Declare it (Content-Type: application/json; charset=utf-8). Mojibake (Café instead of Café) means one side decoded UTF-8 bytes as Latin-1. Database column encodings, CSV exports, and email are where this still happens.

4. Compression. Accept-Encoding: gzip, br → Content-Encoding: br. Brotli/gzip typically shrink JSON 70–90%. HTTP/2 compresses headers with HPACK (HTTP/3 uses QPACK). Security note: compressing secrets together with attacker-controlled input under encryption enables CRIME/BREACH-style attacks.

Try it yourself

# Full TLS handshake details: protocol, cipher, certificate chain, expiry
openssl s_client -connect shop.example.com:443 -servername shop.example.com </dev/null 2>/dev/null \
  | grep -E 'Protocol|Cipher|subject=|issuer=|Verify return'

# Certificate dates and names (expiry monitoring in one line)
echo | openssl s_client -connect shop.example.com:443 -servername shop.example.com 2>/dev/null \
  | openssl x509 -noout -dates -subject -ext subjectAltName

# Did the server compress the response?
curl -s -o /dev/null -H 'Accept-Encoding: br, gzip' -w '%{size_download} bytes\n' https://shop.example.com/
curl -sI -H 'Accept-Encoding: br, gzip' https://shop.example.com/ | grep -i content-encoding

# Inspect bytes / encoding of a payload
printf 'Café' | xxd        # c3 a9 = é in UTF-8

What breaks

Symptom Presentation cause
Sudden total outage, browsers show NET::ERR_CERT_DATE_INVALID Expired certificate
Works in Chrome, fails in curl/Java/Android Missing intermediate certificate (browsers sometimes fetch it themselves; other clients don't)
Some clients fail TLS, others fine Clock skew on the client; old clients without TLS 1.2+/SNI; cipher mismatch
Wrong certificate served SNI not sent (old client, raw IP), or the wrong default cert on the LB
Order IDs off by one in the UI 64-bit integer in JSON parsed into a JS Number
Café shows as Café UTF-8 decoded as Latin-1 somewhere in the pipeline
gRPC consumer crashes after a deploy Protobuf field number reused or type changed

War story: "The certificate that expired on a Saturday"

A company's API certificate was renewed manually every year by one engineer, who left. On a Saturday the certificate expired. Every mobile app version pinned to that certificate's public key also broke, and fixing that needed an app-store release that took four days. Fixes: automated issuance and renewal (ACME / cloud certificate manager), expiry monitoring alerting 30 days ahead, and pinning the CA/intermediate key rather than the leaf, with a backup pin. Lesson for managers: certificate expiry is one of the most common preventable outages. Track it as an owned, monitored asset, not tribal knowledge.

Why it matters to you

  • Decide where TLS terminates, and say so. At the CDN? The LB? The pod (end-to-end / mTLS via a service mesh)? Every terminating hop can read plaintext. That's a compliance (PCI/HIPAA) and threat-model decision.
  • Encoding and serialisation are API contracts. Put them in your API guidelines: UTF-8, ISO-8601 timestamps in UTC, string IDs, explicit nulls vs missing fields, protobuf evolution rules.
  • Automate certificates end to end. A manual certificate is an incident on a timer.

Go deeper in the series


Generated from real-life-example-osi.md · 8 Oct 2026 16:36