跳至主要內容
Skip to content

Auth Audit Log 設計

身份系統不是只要「擋住攻擊」。

它還要能在事後回答:

text
誰登入了?
誰失敗了?
誰改了密碼?
誰停用了 MFA?
誰新增了管理員?
誰看了敏感資料?
誰匯出了資料?
誰用哪個 session 做了哪個高風險操作?

如果回答不出來,系統就算功能正常,也很難說是安全的。

Auth Audit Log 的核心不是:

text
console.log 一下。

而是建立一套可以支援:

  • 安全調查。
  • 使用者通知。
  • 異常偵測。
  • 法規稽核。
  • 事故應變。
  • 內部濫權追蹤。
  • 高風險操作證據保存。

的事件紀錄系統。

OWASP Logging Cheat Sheet 也強調,應記錄具有安全意義的事件,例如 authentication successes/failures、authorization failures、敏感資料存取、管理員功能使用、權限變更等。也就是說,Auth Audit Log 是身份系統的安全感測器。

一、 一句話回答

如果面試官問:

Auth Audit Log 要怎麼設計?

可以先回答:

Auth Audit Log 要記錄所有和身份、Session、權限、安全設定與敏感操作有關的事件,例如註冊、登入成功/失敗、登出、MFA 驗證、忘記密碼、密碼變更、Session 撤銷、第三方登入綁定、權限變更、重新驗證、資料匯出與管理員操作。每筆事件應包含 actor、target、action、result、time、IP、user agent、session id、request id、risk score、驗證方式與必要 metadata,但不能記錄密碼、OTP、完整 token、完整敏感資料。Log 要不可被一般管理員任意修改或刪除,支援查詢、告警、保留政策與隱私最小化;高風險事件要能即時通知或送 SIEM。

短一點可以說:

text
Auth Audit Log 是身份系統的黑盒子:
出事時要能還原誰在什麼時間,用什麼身份,對什麼資源做了什麼。

二、 Audit Log 和一般 Log 差在哪

一般 application log 常用來 debug:

text
API latency
SQL error
stack trace
request failed

Auth Audit Log 則是安全證據:

text
user login success
password changed
mfa disabled
role granted
session revoked
sensitive data exported

比較:

類型目的保存重點
Access LogHTTP 請求紀錄method、path、status、latency
Application LogDebug / 運維error、trace、business state
Security Log安全事件偵測attack、blocked、risk
Auth Audit Log身份與權限證據actor、action、target、result、time

它們可以送到同一個 log 平台,但語意要分清楚。

Audit log 不應該只是散落在應用程式 log 裡的文字。

它應該是結構化事件。

三、 什麼事件一定要記

身份系統至少要記這些。

1. 註冊與身份建立

  • 註冊成功。
  • 註冊失敗。
  • Email 驗證成功/失敗。
  • 手機驗證成功/失敗。
  • 重寄驗證信。
  • 邀請成員。
  • 接受邀請。
  • 帳號啟用。
  • 帳號停用。

2. 登入與登出

  • 登入成功。
  • 登入失敗。
  • 登入被 rate limit。
  • 帳號被 lock / unlock。
  • 登出目前裝置。
  • 登出所有裝置。
  • Session timeout。
  • Session 被管理員撤銷。

3. MFA 與高強度驗證

  • MFA 啟用。
  • MFA 停用。
  • MFA 驗證成功/失敗。
  • Backup codes 產生。
  • Backup code 使用。
  • Passkey 新增/刪除。
  • TOTP secret reset。
  • Step-up authentication 成功/失敗。

4. 密碼與帳號恢復

  • 忘記密碼請求。
  • reset token 產生。
  • reset token 使用成功/失敗。
  • 密碼修改。
  • 帳號恢復開始。
  • 帳號恢復成功/失敗。
  • 安全聯絡方式變更。

5. 第三方登入與 SSO

  • 第三方登入成功/失敗。
  • external identity 綁定。
  • external identity 解除。
  • SSO 登入成功/失敗。
  • IdP group / role mapping 變更。
  • OIDC / SAML assertion 驗證失敗。

6. 權限與管理員操作

  • 角色授予。
  • 角色撤銷。
  • 權限變更。
  • 新增管理員。
  • 停用管理員。
  • 管理員 MFA reset。
  • IP allowlist 變更。
  • 安全政策變更。
  • Break-glass account 使用。

7. 敏感資料與高風險操作

  • 查看完整個資。
  • 查看醫療資料。
  • 匯出資料。
  • 下載報表。
  • 修改收款帳號。
  • 大額交易。
  • 醫療授權。
  • 文件簽章。
  • impersonation 開始/結束。

這些事件不一定都屬於 Auth Service,但都和身份、權限與安全責任相關。

四、 Event Schema

Audit log 最重要的是欄位穩定。

可以設計成:

ts
type AuthAuditEvent = {
  id: string
  eventType: string
  action: string
  result: 'success' | 'failure' | 'denied' | 'pending'

  actorType: 'user' | 'admin' | 'system' | 'service'
  actorId?: string
  targetType?: string
  targetId?: string

  sessionId?: string
  requestId: string
  correlationId?: string

  ip?: string
  userAgent?: string
  deviceId?: string
  geo?: string

  authMethod?: string
  mfaMethod?: string
  assuranceLevel?: string
  reauthRequired?: boolean
  reauthMethod?: string

  riskScore?: number
  reason?: string
  metadata?: Record<string, unknown>

  occurredAt: string
  recordedAt: string
}

資料庫概念:

sql
create table auth_audit_logs (
  id uuid primary key,
  event_type text not null,
  action text not null,
  result text not null,

  actor_type text not null,
  actor_id uuid,
  target_type text,
  target_id text,

  session_id uuid,
  request_id text not null,
  correlation_id text,

  ip inet,
  user_agent text,
  device_id text,
  geo text,

  auth_method text,
  mfa_method text,
  assurance_level text,
  reauth_required boolean,
  reauth_method text,

  risk_score integer,
  reason text,
  metadata jsonb,

  occurred_at timestamp not null,
  recorded_at timestamp not null
);

欄位說明:

欄位用途
event_type分類,例如 auth.login
action具體動作,例如 login
result成功、失敗、拒絕、等待中
actor誰做的
target影響誰或什麼資源
session_id哪個 session
request_id單次 API 請求追蹤
correlation_id跨服務流程追蹤
ip/user_agent/device來源上下文
auth_method/mfa_method使用哪種驗證
assurance_level當時驗證強度
risk_score風控判斷
metadata事件特有補充資訊

五、 Event Naming

事件命名要穩定、可搜尋。

建議用階層式命名:

text
auth.register.success
auth.login.success
auth.login.failure
auth.logout.success
auth.password.reset_requested
auth.password.changed
auth.mfa.enabled
auth.mfa.disabled
auth.session.revoked
auth.reauth.success
auth.external_identity.linked
auth.role.granted
auth.admin.created
auth.data.export_requested
auth.sensitive_data.viewed

也可以拆成:

text
category = auth
action = login
result = success

重點是:

  • 不要今天叫 login_fail,明天叫 LOGIN_FAILED
  • 不要把重要語意塞在 message 字串裡。
  • 不要用自然語言當唯一查詢依據。
  • 要能讓 SIEM / dashboard / alert rule 穩定使用。

六、 不該記什麼

Audit log 很重要,但不能變成另一個資料外洩點。

不要記:

  • 明文密碼。
  • OTP。
  • TOTP secret。
  • recovery code 明文。
  • reset token 明文。
  • access token / refresh token 完整值。
  • session id 原始值。
  • 私鑰。
  • 完整信用卡號。
  • 完整病歷內容。
  • 過多個資。

可以記:

  • token hash prefix。
  • session id hash。
  • user id。
  • resource id。
  • masked email / phone。
  • metadata 裡的安全摘要。

例如:

json
{
  "eventType": "auth.password.reset_requested",
  "actorType": "anonymous",
  "targetType": "user",
  "targetId": "user_123",
  "metadata": {
    "emailMasked": "a***@example.com"
  }
}

不要:

json
{
  "resetToken": "raw-token-value"
}

OWASP ASVS 和 Logging Cheat Sheet 都強調,不應把敏感資料寫進 log,並且 log 本身也要有存取控制。

七、 成功與失敗都要記

只記成功是不夠的。

很多攻擊訊號都在失敗裡:

  • 密碼錯誤。
  • MFA 失敗。
  • OTP 猜測。
  • reset token 失敗。
  • session 無效。
  • 權限不足。
  • CSRF token 失敗。
  • rate limit 觸發。

例如登入失敗:

json
{
  "eventType": "auth.login.failure",
  "result": "failure",
  "actorType": "anonymous",
  "targetType": "user",
  "targetId": "user_123",
  "ip": "203.0.113.10",
  "reason": "invalid_password",
  "riskScore": 42
}

但要注意:

text
對外錯誤訊息要避免帳號枚舉,
對內 audit log 可以記錄更細 reason。

也就是:

text
使用者看到:帳號或密碼錯誤
內部記錄:user exists, invalid password

內部 log 的存取權限要嚴格。

八、 Actor 和 Target 要分清楚

Audit log 最常見的坑是:

text
只記 user_id。

但很多事件有 actor 和 target。

例如管理員停用使用者:

text
actor = admin_1
target = user_9
action = disable_user

管理員 impersonate 使用者:

text
actor = admin_1
target = user_9
effective_user = user_9

系統自動撤銷 session:

text
actor = system
target = user_9
reason = risk_detected

如果只記一個 user_id,事後會分不清:

text
這件事是使用者本人做的?
管理員替他做的?
系統自動做的?

所以資料模型要明確支援:

  • actor。
  • target。
  • resource。
  • effective subject。
  • reason。

九、 Request ID 與 Correlation ID

身份流程常常跨多個服務。

例如:

text
API Gateway
-> Auth Service
-> Risk Engine
-> MFA Service
-> Session Store
-> Notification Service

如果每個服務各記一筆 log,但沒有共同 ID,就很難串起來。

建議:

ID用途
request_id單一 HTTP request
correlation_id一整個業務流程
session_id同一登入狀態
auth_event_id同一身份驗證事件
trace_id分散式 tracing

例如登入加 MFA:

text
login request
-> password verified
-> mfa challenge created
-> mfa verified
-> session created

它們可以共享同一個 correlation_id

十、 Storage 設計

Audit log 的儲存要考慮:

  • 寫入量。
  • 查詢需求。
  • 保留時間。
  • 防竄改。
  • 成本。
  • 隱私。
  • 告警延遲。

常見架構:

小系統可以直接寫資料庫。

大系統建議用 event queue,避免 audit 寫入拖慢主流程。

但高風險事件要注意:

text
不能因為 queue 掛了就完全沒有紀錄。

可考慮:

  • 本地 fallback log。
  • 重試機制。
  • dead letter queue。
  • 寫入失敗告警。
  • 對關鍵事件採同步或半同步寫入。

十一、 防竄改與存取控制

Audit log 如果可以被攻擊者刪掉,就失去價值。

應該考慮:

  • Append-only。
  • 一般管理員不能修改/刪除。
  • 刪除或匯出 log 也要被記錄。
  • 定期歸檔。
  • 寫入獨立儲存。
  • Object storage versioning / retention lock。
  • hash chain 或簽章,依需求。
  • 權限最小化。

例如高信任系統可以設計:

text
application writes audit event
-> audit writer append-only
-> daily file hash
-> hash 保存到獨立位置
-> archive 加 retention policy

不一定每個產品都要做到這麼重。

但至少要避免:

text
super admin 在後台按一下就刪掉自己的 audit log。

十二、 Retention 與隱私

Audit log 要保存多久?

答案不是越久越好。

要看:

  • 法規。
  • 風險等級。
  • 使用者隱私。
  • 儲存成本。
  • 事故調查需求。
  • 資料刪除需求。

可以分層:

類型保存策略
一般登入事件例如 90 天到 1 年,依需求
高風險安全事件更長保存
管理員操作通常更長保存
金融/醫療敏感操作依法規與合約要求保存
Debug log短期保存

也要處理:

  • 使用者刪除帳號後 audit log 是否保留。
  • 保留時是否 pseudonymize。
  • metadata 是否含個資。
  • 查詢權限是否受控。

工程上可以把:

text
user_id

保留為內部識別碼,但移除不必要的 email、phone、姓名等可讀個資。

十三、 Alerting

Audit log 如果只存不看,效果有限。

應該建立告警規則。

常見告警:

事件告警
同帳號多次登入失敗可能暴力破解
多帳號同 IP 失敗可能 credential stuffing
MFA 連續失敗可能攻擊或使用者被釣魚
新裝置登入通知使用者
密碼修改通知使用者
MFA 停用高風險通知
新增管理員安全團隊告警
權限提升安全團隊告警
大量資料匯出即時告警
Break-glass 使用Critical 告警
Audit writer 停止Critical 告警

告警要有等級:

text
info
low
medium
high
critical

不要所有事件都打爆 Slack。

否則團隊會麻木。

十四、 User Notification

有些 audit event 應通知使用者。

例如:

  • 新裝置登入。
  • 密碼變更。
  • Email / 手機變更。
  • MFA 停用。
  • 新增 Passkey。
  • 第三方登入綁定。
  • 大額交易。
  • 資料匯出。

通知內容:

  • 發生時間。
  • 操作類型。
  • 大略裝置或地點。
  • 如果不是本人該怎麼處理。

不要放:

  • 完整 token。
  • 完整信用卡號。
  • 完整病歷。
  • 過多敏感資料。

通知本身也可能造成資訊外洩,要小心設計。

十五、 Audit Log API

後台查 audit log 也要控權。

API 範例:

text
GET /admin/audit-logs?actorId=&targetId=&eventType=&from=&to=
GET /admin/audit-logs/:id
POST /admin/audit-logs/export

查詢 audit log 應該:

  • 只有特定角色可查。
  • 查詢也要被記錄。
  • 匯出要重新驗證。
  • 匯出檔短效。
  • 敏感欄位遮蔽。
  • 大量查詢告警。

不要讓一般客服可以自由查所有安全 log。

尤其是金融/醫療場景。

十六、 實作範例

可以建立一個統一 writer:

ts
type AuditInput = {
  eventType: string
  action: string
  result: 'success' | 'failure' | 'denied'
  actorType: 'user' | 'admin' | 'system'
  actorId?: string
  targetType?: string
  targetId?: string
  sessionId?: string
  requestId: string
  ip?: string
  userAgent?: string
  riskScore?: number
  metadata?: Record<string, unknown>
}

async function recordAuthAudit(input: AuditInput) {
  const sanitized = sanitizeAuditMetadata(input.metadata)

  await auditLogStore.insert({
    ...input,
    metadata: sanitized,
    occurredAt: new Date(),
    recordedAt: new Date()
  })
}

在登入失敗時:

ts
await recordAuthAudit({
  eventType: 'auth.login.failure',
  action: 'login',
  result: 'failure',
  actorType: 'anonymous',
  targetType: 'user',
  targetId: user?.id,
  requestId: req.id,
  ip: req.ip,
  userAgent: req.headers['user-agent'],
  riskScore,
  metadata: {
    reason: 'invalid_password'
  }
})

在管理員變更角色時:

ts
await recordAuthAudit({
  eventType: 'auth.role.granted',
  action: 'grant_role',
  result: 'success',
  actorType: 'admin',
  actorId: admin.id,
  targetType: 'admin_user',
  targetId: targetAdmin.id,
  sessionId: admin.sessionId,
  requestId: req.id,
  ip: req.ip,
  metadata: {
    role: 'finance_admin',
    reason: req.body.reason
  }
})

十七、 常見錯誤

1. 只記登入成功

錯誤:

text
login success 才寫 log。

正確:

text
登入成功、失敗、rate limit、MFA 失敗、權限拒絕都要記。

2. Log 裡有敏感資料

錯誤:

text
metadata 裡放 password、otp、token。

正確:

text
敏感秘密絕不進 log,必要時只存 hash 或 masked value。

3. 沒有 actor / target

錯誤:

text
只記 user_id。

正確:

text
分清楚誰做的、影響誰、作用在哪個 resource。

4. 沒有 request id

錯誤:

text
各服務 log 串不起來。

正確:

text
每筆 audit event 有 request_id / correlation_id。

5. Audit log 可以被同權限刪除

錯誤:

text
管理員可以刪掉自己的操作紀錄。

正確:

text
Audit log 應 append-only 或至少限制修改刪除,並記錄查詢與匯出。

6. 只存不告警

錯誤:

text
log 都在,需要時再查。

正確:

text
高風險事件要即時告警,否則事故發生時已經太晚。

十八、 面試追問題庫

Q1:Auth Audit Log 要記哪些事件?

註冊、登入成功/失敗、登出、MFA、忘記密碼、密碼變更、Session 建立/撤銷、第三方登入綁定、權限變更、管理員操作、重新驗證、敏感資料存取與資料匯出。

Q2:Audit log 欄位怎麼設計?

至少包含 event type、action、result、actor、target、session id、request id、IP、user agent、auth method、MFA method、assurance level、risk score、reason、metadata、occurred_at。

Q3:Log 裡不能放什麼?

不能放明文密碼、OTP、TOTP secret、recovery code、reset token、access token、refresh token、session id 原文、私鑰、完整信用卡號、完整病歷或過多敏感個資。

Q4:登入錯誤訊息不能透露帳號存在,那 audit log 可以記嗎?

可以。對外回應應避免帳號枚舉,但內部 audit log 可以記更精細的原因,例如帳號存在但密碼錯誤。不過 log 存取必須嚴格控管。

Q5:Audit log 如何防竄改?

可以使用 append-only 儲存、限制修改刪除、獨立權限、歸檔、object lock、hash chain 或簽章。至少要避免一般管理員能刪除自己的紀錄。

Q6:Audit log 和 alerting 的關係?

Audit log 是事件來源,alerting 是即時偵測。高風險事件如 MFA 停用、新增管理員、大量資料匯出、break-glass 使用、audit writer 停止,都應觸發告警。

Q7:為什麼要分 actor 和 target?

因為很多操作不是本人對自己做的,例如管理員停用使用者、系統撤銷 session、客服 impersonate 使用者。actor 和 target 分開才能事後追責。

十九、 實作題

題目一:設計登入 audit log

好的答案:

  • 登入成功和失敗都記。
  • 記 actor / target。
  • 記 IP、user agent、device。
  • 記 session id hash。
  • 記 MFA 是否成功。
  • 記 risk score。
  • 對外錯誤訊息一致,內部 reason 詳細。
  • 多次失敗觸發告警。

題目二:設計管理員權限變更 log

好的答案:

  • actor_admin_id。
  • target_admin_id。
  • granted / revoked role。
  • reason。
  • step-up method。
  • request_id。
  • IP / user agent。
  • result。
  • 安全團隊告警。

題目三:設計敏感資料匯出 log

好的答案:

  • actor。
  • resource scope。
  • row count。
  • fields exported。
  • purpose。
  • reauth method。
  • file id。
  • expires_at。
  • result。
  • 大量匯出告警。

題目四:設計不可竄改 audit log

好的答案:

  • 應用寫入 queue。
  • Audit writer 以 append-only 寫入。
  • 歸檔到 object storage。
  • 啟用 retention / versioning。
  • 每批 log 計算 hash。
  • 查詢與匯出 log 也記錄。
  • 寫入失敗告警。

二十、 資深視角

1. Audit Log 是產品能力,不只是資安需求

它不只給安全團隊看。

客服、法務、合規、SRE、產品營運都可能需要它回答問題。

但不同角色看到的欄位和範圍要不同。

2. Log 的價值在查得到

只存一大堆 JSON 不代表能稽核。

要能查:

  • 某使用者最近所有登入。
  • 某管理員最近所有高風險操作。
  • 某 IP 對多少帳號失敗登入。
  • 某筆資料被誰看過。
  • 某次事故相關的所有 request。

所以事件命名、索引、欄位設計很重要。

3. Audit Log 自己也是敏感資料

Audit log 會包含使用者行為、IP、裝置、資料存取紀錄。

它本身也是高敏感資料。

因此要有:

  • 存取控制。
  • 查詢稽核。
  • 保留政策。
  • 遮蔽。
  • 匯出限制。

4. 沒有告警的 Audit Log 只能事後懊悔

事故發生後查 log 很重要。

但更好的系統會在事故擴大前告警。

例如:

text
新增管理員 + 凌晨登入 + 大量資料匯出

這些事件分開看都可能合理,串起來就很可疑。


總結

面向設計重點
事件範圍登入、登出、MFA、密碼、Session、權限、敏感操作
Schemaactor、target、action、result、time、request id、risk
敏感資料不記密碼、OTP、token、完整敏感資料
成功/失敗兩者都要記,失敗是攻擊訊號
Actor/Target分清本人、管理員、系統、被影響資源
Correlationrequest id、correlation id、session id 串事件
Storage結構化、可查詢、可歸檔、可告警
防竄改append-only、權限隔離、歸檔、hash / retention
Retention依風險、法規、隱私與成本分層
Alerting高風險事件即時告警

一句完整的面試回答可以是:

Auth Audit Log 要記錄身份系統中所有安全相關事件,包括註冊、登入成功與失敗、登出、MFA、忘記密碼、密碼變更、Session 撤銷、第三方登入綁定、權限變更、重新驗證、管理員操作與敏感資料存取。每筆 log 應是結構化事件,包含 actor、target、action、result、時間、IP、user agent、session id、request id、驗證方式、assurance level、risk score 與必要 metadata。Log 不能包含密碼、OTP、token 或完整敏感資料,並且要有存取控制、防竄改、保留政策和查詢能力。高風險事件例如 MFA 停用、新增管理員、大量匯出、break-glass 使用,應即時告警。

延伸閱讀