What is Security and Privacy
Security is the discipline of making the cost of violating three concrete properties higher than any realistic attacker will pay: confidentiality (only intended parties can read the bytes), integrity (bytes cannot be altered undetected), and availability (the legitimate owner can still use the system). Privacy is a narrower, orthogonal question layered on top: even among parties authorized to see data, what can they lawfully derive about a person, and for how long? You do not "add security" — you place enforcement at every trust boundary (the seam where data crosses from a party you control to one you do not: browser↔server, service↔service, app↔disk) and make each crossing prove identity and protect the payload with cryptography.
Every mechanism in this section is one enforcement primitive at one boundary. It helps to hold the whole map in your head before drilling in:
| Question at the boundary | Property it defends | Primitive | Concrete tool |
|---|---|---|---|
| Who are you? | Integrity of identity | Authentication | TLS certificate, JWT, Kerberos ticket, mTLS |
| What may you do? | Confidentiality + integrity | Authorization | RBAC / ABAC, OAuth scopes, ACLs |
| Can anyone read this on the wire? | Confidentiality | Encryption in transit | TLS 1.3 (AES-GCM), IPsec |
| Can anyone read this on the disk? | Confidentiality | Encryption at rest | AES-256, envelope encryption + KMS |
| Was this message tampered with? | Integrity | MAC / signature | HMAC-SHA256, RSA/ECDSA signatures |
| Is someone attacking right now? | Availability | Detection & response | IDS/IPS, rate limits, WAF, anomaly logs |
A useful lens for finding the boundaries you forgot is STRIDE — for each data flow ask whether it is exposed to Spoofing (defeated by authn), Tampering (integrity/MACs), Repudiation (audit logs), Information disclosure (encryption), Denial of service (rate limits, quotas), and Elevation of privilege (authorization). The rest of this page traces two of these primitives end to end with real bytes.
Principles that shape every boundary
- Least privilege. Every identity — human, service, or workload — should receive only the minimum access and only for the minimum time. A token that can read every service when it only needs two is a breach waiting to scale.
- Defense in depth. No single control is perfect; layer independent controls so a bug in one does not open the whole system. A SQL-injection bug behind a WAF is still a bug; the WAF just buys time.
- Zero trust. "Inside the network" is not a trust zone. Authenticate and authorize every crossing, including service-to-service calls, with short-lived, auditable credentials.
- Secure by default / fail secure. The safe posture must be the default posture: deny by default, reject unknown algorithms, expire sessions, and fail closed rather than open.
These principles are worked through concretely in Securing a System — Defense in Depth, Layer by Layer.
Worked walkthrough: STRIDE on a photo-upload API
Suppose you are designing POST /upload for a photo-sharing app. The data flows are: browser → CDN edge → upload API → object storage (S3), and upload API → thumbnail worker → metadata database. Walk each flow through STRIDE and name a concrete control.
| Threat | Where it hides | Control | If you skip it |
|---|---|---|---|
| Spoofing | Attacker calls /upload with a stolen session cookie or forged JWT | Bearer token validation + short expiry + TLS | Anyone can upload or delete as another user |
| Tampering | MitM replaces the image bytes in transit; client manipulates EXIF metadata | TLS 1.3 for transit; server-side re-sanitization of metadata | Uploaded content is not what the real user sent |
| Repudiation | User denies uploading an abusive image | Immutable audit log with request ID, user ID, timestamp, object key | No evidence for abuse investigations |
| Information disclosure | S3 bucket is world-readable; thumbnails leak location in EXIF | Private bucket + signed URLs; strip EXIF before serving | Private photos and location data become public |
| Denial of service | Attacker uploads a 10 GB “photo” or floods the endpoint | Rate limits per user/IP; size caps; async quarantine scan | Storage bills explode and API falls over |
| Elevation of privilege | User passes album_id=999 they do not own | Object-level authorization check before accepting the upload | Users write into other users’ albums (IDOR) |
The point is not to memorize the table; it is that every data flow gets a control, and the controls are independent so one failure does not collapse the whole system.
Defense in depth: layers and what each layer catches
Defense in depth means an attacker has to chain multiple failures before reaching the asset. For the same upload API, the layers look like this:
| Layer | Example control | Catches... | Missing layer’s cost |
|---|---|---|---|
| Edge / network | WAF, DDoS scrubbing, TLS termination, GeoIP blocks | Volumetric floods, malformed HTTP, protocol attacks | A simple flood takes the API offline |
| Identity | Token validation, MFA for account changes | Stolen credentials, session replay | Compromised user becomes the attacker |
| Authorization | Object-level ownership check, OAuth scopes | IDOR, lateral movement | Authenticated users can touch anything |
| Application | Input validation, size limits, content-type enforcement | Malformed files, injection, business-logic abuse | A single bad request corrupts data or crashes workers |
| Data | Encryption at rest, least-privilege DB credentials, envelope encryption for keys | Stolen disk snapshots, DB credential leaks | A backup copy is the breach |
| Detection | Audit logs, anomaly detection, rate-limit alerts | Successful attacks that slipped through | You do not know you were breached until too late |
Each layer buys time and reduces blast radius. A WAF bypass is bad, but it is not a total loss if the app still validates input and the database still enforces least privilege.
Worked example: one HTTPS request, byte by byte
A browser calls GET https://api.example.com/me carrying a bearer token. That single line triggers two independent mechanisms at two boundaries: a TLS 1.3 handshake that gives confidentiality + server authentication on the wire, and a JWT verification at the server that gives caller authentication. Here is the TLS handshake (the common 1-RTT case), traced with representative values:
- ClientHello → browser sends its cipher preferences (
TLS_AES_128_GCM_SHA256) and akey_share: a fresh ephemeral X25519 public keyCa = a·Gwhereais a random 32-byte scalar it just generated and throws away after the connection. - ← ServerHello picks the cipher and returns its own ephemeral key
Cb = b·G. Both sides now compute the identical shared secretZ = a·Cb = b·Ca(the Diffie–Hellman identity) withoutZever crossing the wire. - Both run
Zthrough HKDF to derive symmetric handshake keys, then application keys (client_write_key,server_write_key, plus IVs). Everything after ServerHello is already encrypted. - ← Certificate + CertificateVerify: the server sends its X.509 cert chain and a signature, made with the cert's private key, over a hash of the whole transcript so far. The browser walks the chain to a trusted CA and checks that signature. This is what stops a man-in-the-middle: an attacker can relay bytes but cannot produce that signature without the private key.
- Finished → both sides send a MAC over the transcript; if either disagrees, the connection aborts. Now
GET /meflows as AES-128-GCM ciphertext — an AEAD, so each record is both encrypted and integrity-tagged.
Notice what each step buys: the ephemeral keys give forward secrecy (steal the server's long-term key tomorrow and you still cannot decrypt today's captured traffic, because a and b are gone); the certificate signature gives server authentication; AES-GCM gives per-record confidentiality + integrity.
The second boundary: verifying the JWT
TLS proved the server's identity and hid the request, but the server still does not know who is calling. That is the token's job. A JWT is three base64url parts joined by dots — header.payload.signature — and here is a real HS256 token this guide computed (secret = s3rver-hmac-key):
header = {"alg":"HS256","typ":"JWT"}
→ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
payload = {"sub":"user:42","exp":1751500000}
→ eyJzdWIiOiJ1c2VyOjQyIiwiZXhwIjoxNzUxNTAwMDAwfQ
sig = base64url( HMAC_SHA256( header + "." + payload , secret ) )
→ 0UTvyTLwHBGewL1ejGLx68V0t6GD8kGu6JTIGHKpJXUVerification is not "decrypt the token" (a JWT is signed, not encrypted — anyone can read the payload). It is: recompute the MAC over the received header.payload with the server's key and compare.
expected = HMAC_SHA256(recv_header + "." + recv_payload, secret)
if not hmac.compare_digest(expected, recv_sig): # constant-time!
reject(401)
if payload["exp"] <= now(): # 1751500000 vs clock
reject(401)
if header["alg"] != "HS256": # pin the algorithm
reject(400)
grant(subject = payload["sub"]) # → user:42Why the naive version is wrong. Two lines look harmless and are catastrophic. (1) Comparing signatures with expected == recv_sig returns as soon as bytes differ, so response time leaks how many leading bytes matched — an attacker forges the signature one byte at a time. Use a constant-time compare (hmac.compare_digest). (2) Trusting header["alg"] instead of pinning it enables the classic alg:none and RS256→HS256 confusion attacks, where the attacker sets the algorithm to one the verifier accepts with a key it controls. Always decide the algorithm from server config, never from the attacker-supplied header.
Pitfalls
- Encrypting in transit but not at rest (or vice-versa). TLS protects the wire; a stolen disk snapshot or a leaked DB backup is a separate boundary. Both are needed, and "encrypted at rest" is worthless if the key sits next to the data on the same host.
- Confusing authentication with authorization. A valid JWT proves who, not what they may do. The most common real breach is broken object-level authorization (IDOR): an authenticated
user:42requests/orders/999and the server returns someone else's order because it verified the token but never checked ownership. - Long-lived, un-revocable tokens. Stateless JWTs cannot be un-issued; a leaked token is valid until
exp. Keep access tokens short (minutes) and pair with a revocable refresh token, or you have no kill switch. - Trusting the network perimeter. "It's behind the VPC/firewall so it's safe" fails the moment one internal service is compromised. Assume the internal network is hostile too (zero-trust); authenticate service-to-service calls.
- Privacy ≠ security. Perfectly encrypted, perfectly authorized logs that retain user IP + precise location forever are a privacy failure even with zero breach. Data minimization and retention limits are separate obligations.
- Rolling your own crypto or verifier. Hand-written signature checks, custom padding, home-grown token formats — this is where the timing bugs and
algconfusion live. Use vetted libraries and let them pin algorithms.
When to use which primitive — and the trade-offs
The recurring senior-engineer decisions in this section are not "should I have security" but which mechanism at which boundary. Three that come up constantly:
Symmetric vs. asymmetric encryption
Symmetric (AES, HMAC) is one shared key, ~100–1000× faster, and ideal for bulk data — but both parties must already share the secret, which does not scale to strangers. Asymmetric (RSA, ECDH, ECDSA) solves key distribution and authentication with a public/private pair, at the cost of heavy math per operation. Choose symmetric for the bulk payload once a session exists; choose asymmetric only to bootstrap identity and agree on a symmetric key. TLS 1.3 is exactly this hybrid: asymmetric handshake, symmetric AES-GCM for the actual traffic. Reaching for RSA to encrypt a 2 MB body is the classic mistake.
Bearer tokens (JWT/OAuth) vs. mutual TLS for caller identity
Choose bearer JWTs at the edge, where the caller is an end user through a browser or mobile app: they carry claims (sub, scopes, roles) the app needs, work over plain HTTPS, and are cheap to verify statelessly. The cost is that a bearer token is a password-equivalent — anyone holding it is authenticated, so it demands short lifetimes and careful storage. Prefer mTLS for service-to-service traffic inside a mesh: each side presents a certificate, so identity is bound to a key that never leaves the host and there is no bearer secret to steal or replay. The cost is operational — you now run a certificate authority and rotate short-lived certs (this is what Istio/SPIFFE automate). A blunt rule: humans and third parties → tokens; your own services talking to each other → mTLS.
Detect-and-respond (IDS/IPS) vs. prevent-by-construction
Cryptographic controls prevent a class of attack outright; an IDS/IPS detects what slips through and buys response time. They are not alternatives — you layer them (defense in depth). Lean on prevention (encryption, authz, input validation) for anything you can make structurally impossible; add detection for the residual — credential stuffing, anomalous data exfiltration, novel exploits — that no static control anticipates. Prevention with zero detection means a successful attacker is invisible; detection without prevention means you are merely watching yourself get breached.
Trade-off box: security vs. usability
Security controls have a user-experience price. The senior move is to pay it only where the risk justifies it.
| Security choice | Usability cost | When the cost is worth paying |
|---|---|---|
| Short session TTL (5–15 min) | Users re-authenticate often | High-value accounts, admin consoles, finance apps |
| Strict rate limiting / CAPTCHA | False positives lock out legitimate users | Login and password-reset endpoints under credential-stuffing pressure |
| Mandatory MFA enrollment | Onboarding friction, device-loss recovery | High-value accounts or any account that can move money/data |
| Strict Content-Security-Policy | Third-party scripts/widgets break | Pages that render untrusted user content |
| mTLS for every service call | Certificate rotation, debugging complexity | Service-to-service traffic inside a sensitive/zero-trust network |
The wrong answer is to apply the strictest control everywhere. The right answer is to tie the control to the asset and the threat: public product catalog gets a CDN and TLS; admin panel gets short sessions, MFA, and IP allow-listing.
Takeaways
- Security is enforcing confidentiality, integrity, availability at every trust boundary; walk your data flows with STRIDE to find the boundaries you forgot.
- The canonical HTTPS request runs two independent mechanisms: TLS authenticates the server and protects the pipe; the token authenticates the caller. Neither replaces the other, and neither is authorization.
- Verification bugs, not weak ciphers, cause most real failures — non-constant-time compares, unpinned
alg, and missing object-level authorization checks. Use vetted libraries and pin your assumptions. - Match the primitive to the boundary: symmetric for bulk / asymmetric to bootstrap; JWTs for users / mTLS for services; prevention for the known, detection for the residual.
Related pages
- What is Authentication — the identity-verification primitive this page touches at the JWT boundary.
- What is Authorization — the "what may you do" layer that closes the IDOR gap.
- What is Encryption — symmetric/asymmetric primitives and the TLS handshake in depth.
- Securing a System — Defense in Depth — input validation, WAFs, and layered controls.
- Security Considerations — least privilege applied to service registries and mTLS identity.
- Metrics, Logs & Traces — the audit and detection layer STRIDE's Repudiation column depends on.
- Introduction to the API Gateway Pattern — where CORS preflight handling and edge security policies are covered.
Re-authored/Deepened for this guide. Primary sources: RFC 8446 (TLS 1.3) and RFC 5246 (TLS 1.2) for the handshake and key-schedule mechanics; RFC 7519 (JWT) and RFC 7515 (JWS) for token structure and the alg-confusion class of attacks; the OWASP Top 10 (2021) A01 Broken Access Control and A02 Cryptographic Failures for the real-world failure modes; Microsoft's STRIDE threat-model framing; and the SPIFFE/mTLS service-identity model as popularized by Istio. HMAC-SHA256 values in the JWT trace were computed directly for this page.
🤖 Don't fully get this? Learn it with Claude
Stuck on What is Security and Privacy? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Build the mental picture, not memorization.
I just read a lesson on **What is Security and Privacy** (System Design) and want to truly understand it. Explain What is Security and Privacy from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Socratic — adapts to where you're stuck.
Teach me **What is Security and Privacy** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Active recall exposes what you missed.
Quiz me on **What is Security and Privacy** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Intuition + hook + flashcards for long-term memory.
Help me remember **What is Security and Privacy** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.