Authentication & Security
Interview Context
DS/MLE 面試的 system design 環節越來越常出現 auth 題:你的 model API 誰可以呼叫?dashboard 怎麼登入?pipeline 之間怎麼互相信任?面試官想確認你不只會建模,還能安全地把系統接到公司環境裡 — session vs JWT、OAuth flow、SQL injection 防禦是最常被追問的三個主題。
What You Should Understand
- 能解釋 cookie-based session(server 有狀態)和 token-based auth(stateless)的運作方式與取捨
- 能拆解 JWT 的 header.payload.signature 結構,說明 HS256 vs RS256、expiry/refresh token、以及為什麼 JWT 很難撤銷
- 能一步一步講出 OAuth 2.0 authorization code flow,並區分 OAuth(授權)、OIDC(認證)、SSO(單一登入)
- 知道 API key、bearer token、OAuth client credentials、mTLS、HMAC signature 各自適合的場景
- 能說明 SQL injection、XSS、CSRF 的攻擊原理與對應防禦(parameterized query、escaping/CSP、SameSite cookie)
Session vs Cookie vs Token
How Cookie-Based Sessions Work
Session auth keeps the login state on the server:
- User submits username + password → server verifies credentials.
- Server creates a session record(例如存在 Redis 或 database): session ID → user ID, roles, expiry.
- Server responds with
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Lax. - Browser automatically attaches the cookie on every subsequent request to the same domain.
- Server looks up the session ID → knows who the user is → serves the request.
直覺:cookie 只是「置物櫃鑰匙」,真正的身分資料放在 server 的置物櫃裡。要登出或封鎖使用者,server 直接刪掉那筆 session record 就好 — 即時撤銷是 session 的最大優勢。
How Token-Based Auth Works
Token auth keeps the login state inside the token itself(stateless):
- User logs in → server verifies credentials.
- Server signs a token containing identity claims(user ID, roles, expiry)— typically a JWT.
- Client stores the token and sends it on each request:
Authorization: Bearer eyJhbGci.... - Server verifies the signature and reads the claims — no database lookup needed.
直覺:token 是一張「有防偽簽名的通行證」,證件內容都寫在卡片上。任何一台 server 只要有驗證用的 key 就能檢查,不需要共享 session storage — 這讓 token 在分散式系統和跨服務場景特別好用。
Comparison
| Dimension | Cookie-Based Session | Token-Based (JWT) |
|---|---|---|
| State location | Server (session store) | Client (self-contained token) |
| Horizontal scaling | Needs shared store (Redis) or sticky sessions | Trivial — any server can verify |
| Revocation | Instant — delete the session record | Hard — token valid until expiry |
| CSRF risk | Yes — browser auto-sends cookies | Low if sent via Authorization header |
| XSS risk | Low with HttpOnly cookie (JS cannot read it) | High if token stored in localStorage |
| Cross-domain / mobile / API | Awkward — cookies are domain-bound | Natural fit |
| Payload | Just an opaque ID | Carries claims (roles, user ID, expiry) |
| Best for | Server-rendered web apps, admin dashboards | APIs, microservices, mobile clients, SSO |
常見誤解:JWT 不是 session 的無腦升級
很多候選人以為「JWT 比較新所以比較好」。面試官期待你講出取捨:JWT 換來 stateless scalability,代價是失去即時撤銷能力、token 一旦外洩在過期前都有效。單一 server 的內部工具用 session 往往更簡單也更安全。
JWT Deep Dive
Anatomy: header.payload.signature
A JWT is three base64url-encoded parts joined by dots:
eyJhbGciOiJIUzI1NiJ9 . eyJzdWIiOiI0MiIsImV4cCI6MTcyMH0 . SflKxwRJSMeKKF2QT4fwpM
header payload signature
- Header: metadata — signing algorithm and token type, e.g.
{"alg": "HS256", "typ": "JWT"}. - Payload: the claims — statements about the user and the token itself.
- Signature: cryptographic proof that header + payload have not been tampered with.
For HS256:
Encoded 不等於 Encrypted
JWT 的 payload 只是 base64url 編碼,任何人都能解開來讀。簽名只保證「內容沒被竄改」,不保證「內容保密」。絕對不要把密碼、個資、API secret 放進 JWT payload — 這是面試中一句話就能加分(或扣分)的細節。
Standard Claims
| Claim | Meaning | Example |
|---|---|---|
iss | Issuer — who created the token | auth.company.com |
sub | Subject — the user this token is about | user-42 |
aud | Audience — intended recipient service | ml-api |
exp | Expiration time (Unix timestamp) | 1720000000 |
iat | Issued at | 1719996400 |
nbf | Not valid before | 1719996400 |
jti | Unique token ID — enables denylisting | 9f2c... |
HS256 vs RS256
| Aspect | HS256 (HMAC + SHA-256) | RS256 (RSA + SHA-256) |
|---|---|---|
| Key type | Symmetric — one shared secret | Asymmetric — private signs, public verifies |
| Who can sign | Anyone holding the secret | Only the private key holder |
| Who can verify | Anyone holding the secret(= 也能簽!) | Anyone with the public key |
| Key distribution | Secret must be shared with every verifier | Publish public key via JWKS endpoint |
| Speed | Faster | Slower (asymmetric crypto) |
| Best for | Single service signs and verifies itself | Many services verify tokens from one auth server |
直覺:HS256 像「大家共用同一把鑰匙」— 只要一個 verifier 被入侵,攻擊者就能偽造 token。RS256 把「簽發」和「驗證」的能力分開,auth server 私鑰簽名、下游服務用公鑰驗證,這是 microservices 和 OIDC 的標準做法。
Expiry and Refresh Tokens
Standard pattern — short-lived access token + long-lived refresh token:
| Token | Lifetime | Stored Where | Purpose |
|---|---|---|---|
| Access token | 5–15 minutes | Client memory | Sent on every API call |
| Refresh token | Days–weeks | HttpOnly cookie or secure storage; tracked server-side | Exchange for a new access token |
Flow: access token expires → client calls the token endpoint with the refresh token → server checks the refresh token(server 端有記錄,可以撤銷)→ issues a new access token. Refresh token rotation 每次換發都作廢舊的 refresh token,如果同一個 refresh token 被用兩次 → 代表外洩 → 整條 token family 全部撤銷。
Why You Cannot Easily Revoke a JWT
Stateless 的代價:server 驗證 JWT 時不查資料庫,所以沒有地方可以標記「這張 token 作廢了」。使用者登出、被停權、token 外洩 — 在 exp 到期之前 token 都持續有效。
Mitigations(每一個都是 tradeoff):
| Mitigation | How | Cost |
|---|---|---|
| Short expiry | Access token lives 5–15 min | Needs refresh token machinery |
| Denylist | Store revoked jti in Redis, check on each request | Reintroduces server state — no longer stateless |
| Token versioning | Store a version number per user; bump to invalidate all tokens | One DB/cache read per request |
| Rotate signing key | All tokens die at once | Logs out every user — emergency only |
JWT vs PASETO
| Aspect | JWT | PASETO |
|---|---|---|
| Algorithm choice | Header declares alg — flexible but dangerous | Fixed per protocol version — no negotiation |
| Known footguns | alg: none attack, HS256/RS256 confusion attack | Designed to eliminate those by construction |
| Modes | Signed (JWS) or encrypted (JWE) | local(symmetric encrypted), public(asymmetric signed) |
| Ecosystem | Ubiquitous — every language, OIDC standard | Smaller but growing |
直覺:JWT 最大的歷史問題是「algorithm agility」— token 自己宣告用什麼演算法驗證,寫壞的 library 曾接受 alg: none(不驗簽名)或把 RS256 公鑰當 HS256 secret 用。PASETO 的哲學是把演算法寫死在協定版本裡,讓開發者沒有機會選錯。面試時能講出這個設計動機就是深度的展現。
OAuth 2.0 & SSO
The Four Roles
| Role | Who | Example |
|---|---|---|
| Resource Owner | The user who owns the data | 你 |
| Client | The app requesting access | 一個想讀你 Google Calendar 的排程工具 |
| Authorization Server | Issues tokens after consent | Google 的 OAuth server |
| Resource Server | Hosts the protected data, accepts access tokens | Google Calendar API |
核心觀念:OAuth 2.0 解決的是「委託授權」— 讓第三方 app 拿到一張範圍受限的 access token,而不是把你的密碼交給它。OAuth 本身是 authorization protocol,不是 authentication protocol。
Authorization Code Flow, Step by Step
- Redirect to authorize: client 把 user 的瀏覽器導向 authorization server,帶上
client_id,redirect_uri,scope, 和隨機的state(防 CSRF)。 - User authenticates and consents: user 在 auth server 登入(client 永遠看不到密碼),同意授權畫面列出的 scopes。
- Redirect back with code: auth server 把瀏覽器導回
redirect_uri,附上一次性的短效 authorization code。 - Back-channel token exchange: client 的 server 直接向 token endpoint 送出 code +
client_secret,換回 access token(有時加上 refresh token)。這步走 server-to-server,token 不經過瀏覽器。 - Call the API: client 帶著
Authorization: Bearer access_token呼叫 resource server。
為什麼要多一步 code exchange?因為瀏覽器 redirect 是「front channel」,URL 可能被 log、被 history 記下來。真正值錢的 access token 只在「back channel」傳遞。Public clients(SPA、mobile app)沒有能力保管 client_secret,所以用 PKCE:client 先送 code challenge(隨機值的 hash),換 token 時出示原始值 — 攔截到 code 的攻擊者換不到 token。
OIDC: Identity on Top of OAuth
OAuth 2.0 只回答「這個 app 可以做什麼」,不回答「這個 user 是誰」。OpenID Connect (OIDC) 在 OAuth 上加了一層身分:
- 多回傳一個 ID token(一個 JWT)— 內含
sub,iss,aud,exp等身分 claims。 - 標準化的 userinfo endpoint 和 discovery document。
- 「Sign in with Google」就是 OIDC。
How SSO Works: SAML vs OIDC
SSO 的核心:把「認證」集中到一個 Identity Provider (IdP)。App(Service Provider)不自己驗密碼,而是把 user 轉去 IdP;IdP 有全域 session,第二個 app 來的時候不用重新登入,直接發 token/assertion 回去。
| Aspect | SAML 2.0 | OIDC |
|---|---|---|
| Format | XML assertions | JSON + JWT |
| Transport | Browser POST/redirect bindings | HTTPS redirects + JSON APIs |
| Era / fit | 2005 — enterprise web apps | 2014 — modern web, mobile, APIs |
| Complexity | Heavy (XML signatures, metadata) | Lighter, developer-friendly |
| Typical IdP | Okta, ADFS, Azure AD | Google, Auth0, Keycloak, Azure AD |
實務上:老牌企業內部系統多半接 SAML,新的產品和 API 幾乎都走 OIDC。兩者常常並存在同一個 IdP 上。
Where 2FA Fits In: TOTP Flow
Two-factor authentication 在「密碼驗證成功之後、session/token 簽發之前」插入第二道檢查:
- Enrollment: server 產生一個 shared secret,用 QR code 給 authenticator app(Google Authenticator, 1Password)。
- Code generation: app 每 30 秒算一次 6 位數 code:
- Verification: user 輸入 code → server 用同一個 secret 和目前的 time window 重算比對(通常容忍前後一個 window 的時鐘誤差)→ 通過才建立 session。
SMS OTP 被視為較弱的第二因子(SIM swapping 攻擊),TOTP 或 hardware key(FIDO2/WebAuthn)是面試時該給的答案。
API Authentication Methods
Service 對 service、client 對 API 的認證選項比較:
| Method | How It Works | Security Level | Best For |
|---|---|---|---|
| API Key | Static random string in header; server looks it up | Low–medium — long-lived, no user identity | Server-to-server, usage tracking, rate limiting per caller |
| Bearer Token (JWT) | Signed token with claims and expiry | Medium–high — short-lived, carries identity/roles | User-facing APIs, microservices |
| OAuth 2.0 Client Credentials | Service exchanges client_id + secret for a scoped, short-lived access token | High — central issuance, rotation, scopes, audit | Service-to-service in orgs with an auth server |
| mTLS | Both sides present X.509 certificates during TLS handshake | Very high — identity at transport layer | Zero-trust networks, service mesh (Istio), banking |
| HMAC Request Signing | Client signs method + path + timestamp + body with a shared secret | High — integrity + replay protection | Webhooks, payment APIs (AWS SigV4, Stripe style) |
幾個面試常追問的差異點:
- API key vs token:API key 是「長期有效的靜態身分」,通常代表一個 app 而不是一個 user,沒有內建過期與 scope;token(JWT/OAuth)短效、可帶 claims、可縮小權限範圍。Best practice 是 leveled API keys — 不同權限等級發不同的 key。
- HMAC signing 的獨特價值:它簽的是「整個 request」,所以同時保證 request integrity(body 沒被改)和 anti-replay(timestamp 過期就拒絕)— bearer token 只證明「你有 token」,不保護 request 內容。
- mTLS 把認證下沉到 TLS 層,application code 完全不用管 token,但憑證的簽發與輪換需要 infrastructure(service mesh 幫你做掉這件事)。
Access Control
Authentication vs Authorization
| Question | Term | Example |
|---|---|---|
| Who are you? | Authentication (AuthN) | Login with password + TOTP |
| What can you do? | Authorization (AuthZ) | Can this analyst delete the production table? |
先 AuthN 後 AuthZ — 順序永遠是「先確認身分,再檢查權限」。401 Unauthorized 其實是 authentication 失敗,403 Forbidden 才是 authorization 失敗,這個 HTTP status 的區分也常被面試官順口一問。
RBAC vs ABAC vs ACL
| Model | Grants Access By | Example | Pros | Cons |
|---|---|---|---|---|
| ACL | Explicit list per resource | File X readable by users A, B | Simple, fine-grained | Unmanageable at scale |
| RBAC | Roles assigned to users; permissions attached to roles | data-analyst role can read warehouse | Easy to audit, maps to org structure | Role explosion for complex rules |
| ABAC | Policy over attributes (user, resource, environment) | Allow if user.dept = resource.dept and time is business hours | Extremely flexible, context-aware | Hard to reason about and audit |
實務上 90% 的系統用 RBAC 就夠了;當規則變成「同部門 + 上班時間 + 資料分級 P2 以下」這種多維條件時才升級到 ABAC。
Principle of Least Privilege
每個 user、service、API key 只拿到完成工作所需的最小權限:
- Dashboard 的 DB 帳號只有
SELECT,沒有DROP— SQL injection 發生時 blast radius 有限。 - Pipeline 的 service account 只能寫自己的 output bucket。
- API key 分等級(read-only vs read-write),外洩時損害受控。
這個原則會反覆出現在下面每一種攻擊的防禦裡 — 它不是防止入侵,而是限制入侵後的損害。
Common Attacks & Defenses
SQL Injection
攻擊原理:user input 被字串拼接進 SQL,於是 input 裡的 SQL 語法被當成指令執行。
-- Intended query, user_input = "alice"
SELECT * FROM users WHERE name = 'alice';
-- Attacker sends: ' OR '1'='1' --
SELECT * FROM users WHERE name = '' OR '1'='1' --';
-- WHERE clause is always true: returns every row
Defense — parameterized queries(唯一根治的方法):SQL 語句和資料分開傳給 database driver,input 永遠被當成 value,不可能變成語法。輔助防線:ORM(底層就是 parameterized)、least-privilege DB user、input validation、不把 DB error 原文回給 client。
XSS (Cross-Site Scripting)
攻擊原理:攻擊者的 JavaScript 被注入到頁面裡,在受害者的瀏覽器以該網站的身分執行 — 可以偷 cookie、token、竄改頁面。
| Type | Where the Payload Lives | Example |
|---|---|---|
| Stored | Saved in the database, served to every visitor | Malicious script in a comment field |
| Reflected | Echoed back from the request | Search page prints the query unescaped |
| DOM-based | Never touches the server — client-side JS writes untrusted data into the DOM | innerHTML = location.hash |
Defenses:
- Output escaping / encoding:render 時把 user content 的特殊字元轉義(modern frameworks like React escape by default)。
- Content-Security-Policy (CSP):header 白名單限制 script 來源,禁 inline script → 注入的 script 無法執行。
- HttpOnly cookies:JS 讀不到 session cookie → 就算 XSS 成功也偷不走。
CSRF (Cross-Site Request Forgery)
攻擊原理:瀏覽器對每個 request 自動附上該網域的 cookie。攻擊者的網頁偷偷對 bank.com/transfer 發 POST — 瀏覽器忠實地帶上你的 bank.com session cookie,server 以為是你本人操作。攻擊者不需要偷到 cookie,只需要「借用」它。
Defenses:
- SameSite cookies:
SameSite=Lax(現代瀏覽器預設)讓 cross-site 的 POST 不帶 cookie — 一行設定擋掉大多數 CSRF。 - CSRF token:server 在表單裡埋一個隨機 token,submit 時驗證 — 攻擊者的網站拿不到這個值。
- Check Origin/Referer header:拒絕來源不對的 state-changing request。
- 注意:用
Authorizationheader 送 token 的 API 天然免疫 CSRF(header 不會被瀏覽器自動附上)— 這是 token-based auth 的一個安全優勢。
Attack → Defense Summary
| Attack | Root Cause | Primary Defense | Secondary Defenses |
|---|---|---|---|
| SQL Injection | Input concatenated into SQL | Parameterized queries | ORM, least-privilege DB user, input validation |
| XSS | Untrusted data rendered as HTML/JS | Output escaping | CSP, HttpOnly cookies, framework auto-escaping |
| CSRF | Browser auto-sends cookies cross-site | SameSite=Lax/Strict cookies | CSRF tokens, Origin check, use Authorization header |
| Token theft | Token stored where JS can read it | HttpOnly cookie or in-memory storage | Short expiry, refresh rotation, HTTPS only |
| Replay attack | Captured request re-sent | HMAC signature with timestamp | Nonce tracking, short signature validity |
API Security Checklist
上線一個 model API 或 data service 前的實務清單:
| Item | Why | How |
|---|---|---|
| HTTPS everywhere | Tokens and data in plaintext otherwise | TLS 1.2+, redirect HTTP → HTTPS, HSTS header |
| Auth on every endpoint | One forgotten route = open door | Middleware-level enforcement, deny by default |
| Rate limiting | Brute force, scraping, cost abuse | Token bucket per API key/IP, 429 responses |
| Input validation | Injection, malformed payloads | Schema validation (Pydantic), allowlists, size limits |
| Secrets management | Keys in code leak via git | Vault/Secrets Manager, env injection, rotation schedule |
| Audit logging | Detect abuse, forensics, compliance | Log who did what when — never log tokens or passwords |
| Least-privilege credentials | Limit blast radius | Read-only DB users, scoped tokens, leveled API keys |
| Dependency scanning | Known CVEs in libraries | Dependabot, pip-audit in CI |
面試加分句
「security 是分層防禦(defense in depth)— 沒有單一措施是完美的,所以 parameterized query 之外還要 least-privilege DB user,HttpOnly 之外還要 CSP。」能自然講出這句話,代表你有 security mindset 而不是背清單。
Real-World Use Cases
Case 1: 內部 ML Dashboard — Session 還是 JWT?
你為 data team 建了一個 Streamlit/Dash dashboard 顯示 model metrics,公司要求加上登入。你會選 session 還是 JWT?
分析:這是單一 server、server-rendered、內部使用者的場景 —
- Session 勝出:使用者少(不需要 stateless scaling)、需要即時撤銷(員工離職馬上失效)、HttpOnly session cookie 免疫 XSS 偷 token。
- 更好的答案:不要自己做登入,接公司的 SSO(OIDC)— dashboard 變成 OIDC client,把認證委託給 IdP(Okta/Azure AD),自己只保留一個短效的 local session。員工離職時 IdP 一處停用,全公司系統同步失效。
Interview follow-ups:
- 如果 dashboard 之後拆成 SPA + API,你的選擇會改變嗎?(API 改用短效 JWT,SPA 用 OIDC + PKCE)
- Session store 放哪裡?server 重啟會發生什麼事?(in-memory 會全部登出 → 放 Redis)
- 為什麼 HttpOnly 對這個場景重要?(dashboard 常 render user-generated content,XSS 風險真實存在)
Case 2: Data Pipeline 之間的 Service-to-Service Auth
你的 Airflow DAG 每小時呼叫 feature store API 寫入 features,另外有一個 batch scoring service 讀取。這些 machine-to-machine 呼叫該用 API key 還是 OAuth client credentials?
分析:
- API key:最簡單 — 發一把 key 給 Airflow,API gateway 驗證。適合小團隊、少量 service。缺點:長期有效、rotation 靠人工、權限粒度粗。
- OAuth client credentials flow:每個 service 有 client_id + secret,向 auth server 換短效、有 scope 的 access token(例如
feature-store:write)。集中管理、可審計、token 外洩損害只有幾分鐘。適合 service 數量成長的組織。 - mTLS:如果公司已有 service mesh(Istio/Linkerd),憑證自動輪換,application 層完全不用碰 auth — 但這是 infra 決策,不是 pipeline 團隊自己能選的。
務實的回答:從 leveled API keys 起步(read key vs write key 分開),service 超過一定數量或有 compliance 需求時遷移到 client credentials。
Interview follow-ups:
- API key 要怎麼 rotate 而不中斷 pipeline?(同時接受新舊兩把 key 的 overlap window)
- Secret 存在哪裡?(Vault / cloud secrets manager,注入環境變數,絕不進 git)
- 怎麼發現 key 被濫用?(per-key rate limiting + audit log 上的異常流量告警)
Case 3: SQL 分析工具防注入
你做了一個內部工具:分析師在 UI 選 filter(國家、日期範圍、metric),工具動態組 SQL 查 warehouse。安全風險在哪?
分析:filter 值來自 user input → 直接 f-string 拼進 SQL 就是教科書級的 SQL injection。防禦分三層:
- Values 用 parameterized query — 日期、國家名稱這些「值」全部走 placeholder。
- Identifiers 用 allowlist — column name 和 table name 不能參數化(SQL 語法限制),所以只能對照白名單:user 選的 metric 必須在
{"revenue", "ctr", "dau"}這類預先定義的集合裡,否則拒絕。 - Least-privilege DB user — 工具的 connection 只有特定 schema 的
SELECT權限。就算前兩層都失守,攻擊者也 drop 不了 table。
Interview follow-ups:
- 為什麼 column name 不能用 placeholder?(parameterized query 只能綁定 value,不能綁定 SQL 結構/identifier)
- ORM 就完全安全嗎?(ORM 的
raw()/ string filter 介面一樣可以被注入 — 安全來自 parameterization,不是 ORM 本身) - 查詢結果顯示在網頁上,還有什麼風險?(stored XSS — 資料裡若有 script,render 時要 escape)
Hands-on: Auth & Security in Python
JWT Encode / Decode with PyJWT
import jwt
import datetime
SECRET = "load-this-from-a-secrets-manager" # never hardcode in real code
# Issue a short-lived access token with standard claims
payload = {
"sub": "user-42", # subject: who this token is about
"role": "analyst", # custom claim used for authorization
"iss": "auth.internal", # issuer
"aud": "ml-api", # intended audience
"iat": datetime.datetime.now(datetime.timezone.utc),
"exp": datetime.datetime.now(datetime.timezone.utc)
+ datetime.timedelta(minutes=15), # short expiry limits damage if leaked
}
token = jwt.encode(payload, SECRET, algorithm="HS256")
# Verify: pin the algorithm and audience explicitly
try:
claims = jwt.decode(
token,
SECRET,
algorithms=["HS256"], # never let the token choose its own algorithm
audience="ml-api", # reject tokens minted for other services
)
user_id = claims["sub"] # safe to trust after signature check
except jwt.ExpiredSignatureError:
pass # token expired: client should use its refresh token
except jwt.InvalidTokenError:
pass # tampered, wrong audience, or wrong key: reject with 401
Parameterized SQL vs Vulnerable String Formatting
import sqlite3
conn = sqlite3.connect("analytics.db")
user_input = "alice' OR '1'='1" # attacker-controlled value
# ANTI-PATTERN (do NOT do this): input becomes part of the SQL syntax
# query = f"SELECT * FROM users WHERE name = '{user_input}'"
# conn.execute(query) # WHERE is always true: returns every row
# CORRECT: parameterized query keeps SQL and data separate
rows = conn.execute(
"SELECT * FROM users WHERE name = ?", # ? is a placeholder, not concatenation
(user_input,), # driver binds this strictly as a value
).fetchall() # returns nothing: no user literally named that
# Identifiers (column/table names) cannot be parameterized: use an allowlist
ALLOWED_METRICS = {"revenue", "ctr", "dau"}
metric = "revenue" # value chosen in the UI
if metric not in ALLOWED_METRICS:
raise ValueError("unknown metric") # reject anything outside the allowlist
rows = conn.execute(
f"SELECT {metric} FROM daily_stats WHERE day = ?", # safe: metric was allowlisted
("2026-07-01",),
).fetchall()
HMAC Request Signing
import hmac
import hashlib
import time
SHARED_SECRET = b"per-client-secret-from-vault"
def sign_request(method, path, body, timestamp):
# Sign the whole request: integrity + authenticity in one signature
message = f"{method}\n{path}\n{timestamp}\n{body}".encode()
return hmac.new(SHARED_SECRET, message, hashlib.sha256).hexdigest()
# Client side: attach timestamp and signature as headers
ts = str(int(time.time()))
body = '{"model": "fraud-v3", "features": [0.1, 0.9]}'
signature = sign_request("POST", "/v1/score", body, ts)
# send headers: X-Timestamp: ts, X-Signature: signature
# Server side: recompute and compare
def verify_request(method, path, body, ts, received_sig, max_skew=300):
if abs(time.time() - int(ts)) > max_skew:
return False # stale timestamp: blocks replay attacks
expected = sign_request(method, path, body, ts)
# constant-time comparison prevents timing side-channel attacks
return hmac.compare_digest(expected, received_sig)
Interview Signals
What interviewers listen for:
- 你能講出 session 和 JWT 的核心 tradeoff(即時撤銷 vs stateless scaling),而不是「JWT 比較新所以比較好」
- 你知道 JWT payload 只是編碼不是加密,且能解釋為什麼 revocation 困難、有哪些緩解手段
- 你能一步一步走完 authorization code flow,並說出為什麼 token exchange 要走 back channel
- 被問攻擊時你先講 root cause 再講防禦:SQL injection 是拼接、CSRF 是 cookie 自動附帶、XSS 是未轉義的輸出
- 你會主動提到 least privilege 和 defense in depth,把 auth 決策連回實際場景(誰呼叫、多常、外洩損害多大)
Practice
Flashcards
Flashcards (1/10)
Cookie-based session 和 token-based auth 的核心差異?
Session:狀態存在 server(session store),cookie 只是查詢用的 ID → 可即時撤銷,但 scaling 需要 shared store。Token(JWT):狀態放在 token 本身,server 只驗簽名 → stateless、易水平擴展,但過期前無法撤銷。
Quiz
一個單一 server 的內部 admin dashboard,需要員工離職後立即失去存取權。最適合的 auth 方式?