C.W.K.
Stream
Lesson 05 of 05 · published

Audit Log — The Tamper-Evident Record

~15 min · audit-log, tamper-evident, forensics

Level 0Greenhorn
0 XP0/53 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

The attempts log tracks logins. The audit log tracks privileged actions — the stuff you'd want a record of if anything ever went wrong. Even if you're solo, it's the difference between "I think I did that on Tuesday" and "I know I did that at 14:32 from the laptop".

What to audit

ActionWhy
Login success / failureAlready in attempts; mirror the success rows here
Session revoked (single)Who did it, which session
Revoke All clickedThe biggest hammer; always log
PIN changedMajor security event
IP blacklisted / unblockedManual policy changes
Config changed (max_retry, lockout window)Drift detection
Recovery token usedLast-resort path — always log

Tamper-evidence (for the paranoid)

If you want defense against "the attacker also edited the audit log to hide their tracks", chain rows by hash: each row stores hash(prev_hash + this_row_payload). Periodically copy the latest hash off-server (Dropbox, S3, even a printed sticky note). If the chain breaks on verification, you know.

Code

Audit log schema·sql
CREATE TABLE security_audit (
  id            INTEGER PRIMARY KEY AUTOINCREMENT,
  event         TEXT    NOT NULL,           -- 'revoke_all', 'pin_changed', etc.
  actor_ip      TEXT,                       -- who triggered it
  details       TEXT,                       -- JSON blob for extras
  occurred_at   INTEGER NOT NULL
);
CREATE INDEX idx_audit_time  ON security_audit(occurred_at);
CREATE INDEX idx_audit_event ON security_audit(event);
Audit helper·python
import json, time

def audit_log(event: str, actor_ip: str = None, **details):
    db.execute("""
      INSERT INTO security_audit(event, actor_ip, details, occurred_at)
      VALUES (?, ?, ?, ?)
    """, (event, actor_ip, json.dumps(details), int(time.time())))
    db.commit()

External links

Exercise

Add the security_audit table and the audit_log helper. Wire it into your existing admin endpoints: revoke-all, unblock, kill-ip, incident-mode. Now click each from your admin UI and verify rows appear. The audit log is the answer to 'did I do that, or did someone else?' — invest in it before you need to ask.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.