The previous eight lessons were about prevention: closing doors before anyone crosses them. But no prevention is total. A09:2021 – Security Logging and Monitoring Failures —previously "Insufficient Logging and Monitoring"— addresses what happens when something slips through: do we detect it? how fast? can we investigate what happened? The statistic is damning: many breaches take months to detect, and the alert often comes from outside (a third party, the press) rather than from your own systems.
This category is cross-cutting: it's the one that turns all the "security events" we've been mentioning (access control failures in A01, login attempts in A07, XML with a DTD in XXE...) into actionable signals. In BazarNube we'll review the logging of the Express API: what to log, what to never log (sensitive data), how to detect and alert. This lesson connects directly to the incident analysis case study in module 8 (08-03), where we'll use these logs to reconstruct an attack.
Legal and ethical notice: the examples are illustrative and use fake data. When logging events about real people, comply with the applicable data protection regulations. Practice only on systems you own or have explicit authorization to test.
Contents
- Why logging and monitoring are security
- Which security events to log
- What NOT to log: sensitive data
- How to log well: format, context and correlation
- From logs to detection: alerts and response
- Log integrity and retention
- Common mistakes, exercises and solutions
- Why logging and monitoring are security
Without logging there's no detection (you don't see the attack in progress), no response (you don't know what to contain), no forensic analysis (you can't reconstruct what happened), and no evidence (for legal/regulatory requirements). A good logging system reduces detection time from months to minutes and is the difference between "we contained the incident" and "we found out from the headlines".
- Which security events to log
BazarNube's API barely logged anything relevant for security:
// VULNERABLE by omission: no trace of security events
router.post('/api/login', async (req, res) => {
const u = await getUser(req.body.email);
if (u && await verifyPassword(req.body.password, u.pwd)) {
req.session.userId = u.id;
return res.json({ ok: true });
}
res.status(401).json({ error: 'Invalid credentials' }); // silent failure
});If someone launches a brute force attack (A07), no trace is left. Events that should be logged:
| Event | Why it matters |
|---|---|
| Successful and failed login | Detect brute force / credential stuffing |
| Password, email, MFA changes | Detect account takeover |
| Access control failures (403) | Detect escalation / IDOR attempts (A01) |
| Input validation errors | Possible injections (A03) |
| Sensitive operations (payments, exports, role changes) | Traceability and non-repudiation |
| Administration events | Auditing privileged actions |
| Server errors (500) | Health and possible exploitation |
// SECURE: log security events with context (no sensitive data)
router.post('/api/login', async (req, res) => {
const u = await getUser(req.body.email);
if (u && await verifyPassword(req.body.password, u.pwd)) {
req.session.userId = u.id;
logger.info({ event: 'login_success', userId: u.id, ip: req.ip, reqId: req.id });
return res.json({ ok: true });
}
logger.warn({ event: 'login_failure', emailHash: sha256(req.body.email),
ip: req.ip, reqId: req.id }); // hash of the email, not the email in clear
res.status(401).json({ error: 'Invalid credentials' });
});
- What NOT to log: sensitive data
Over-logging is as serious a security failure as under-logging: logs get copied, sent to third-party systems and kept for a long time. Never log:
- Passwords (not even failed ones), session tokens, API keys, secrets.
- Card data (PAN, CVV) or unnecessary personal data.
- Complete request bodies of sensitive endpoints (they may contain credentials).
// DANGER: this leaks credentials to the log
logger.info('login attempt', { body: req.body }); // body includes the password!When you need to correlate by user without exposing the data, log a pseudonymized identifier (the internal userId, or a hash of the email as above), not the data in the clear. Apply masking (showing only ****4242) and automatic redaction of sensitive fields in the logger.
| Do log | Don't log |
|---|---|
Internal userId, reqId |
Passwords, tokens, keys |
| IP, user-agent, timestamp | PAN/CVV, excessive personal data |
| Event type and result | Complete bodies of sensitive requests |
| Hash/pseudonym of the email | Email/data in clear (if avoidable) |
- How to log well: format, context and correlation
- Structured format (JSON), not free text: it lets you search, filter and alert automatically.
- Enough context: timestamp (UTC), event type, result,
userId, IP, and a correlation id (reqId) that spans all services (React → Express → Java module). - Centralization: send logs to a central system (SIEM / aggregator) to correlate across services and not depend on an ephemeral container keeping its files.
- Consistent levels:
infofor normal events,warnfor suspicious ones,errorfor failures.
flowchart LR A[React Front] -->|reqId| B[Express API] B -->|reqId| C[Java Module] A --> D[Central Log / SIEM] B --> D C --> D D --> E[Correlation and alerts]
The reqId is the thread that lets you reconstruct a complete request across all services: essential for the forensic analysis in module 8.
- From logs to detection: alerts and response
Logging without watching is like installing cameras with no one looking at the screens. You have to detect and alert:
- Correlation rules: "N failed logins for the same account in X minutes", "many 403s from one IP" (possible IDOR enumeration), "spikes of 500 errors".
- Actionable alerts: they should reach whoever can respond (BazarNube's SRE, the security team), with enough context to act and without excessive noise (avoid alert fatigue).
- Thresholds and anomalies: combine fixed rules with anomalous-behavior detection.
- Response plan: an alert must connect to a procedure (who investigates, how it's contained, how it's escalated). Detection without response doesn't close the loop.
- Log integrity and retention
A skilled attacker will try to erase their tracks. That's why:
- Protect integrity: logs in append-only storage or replicated to a system the compromised application can't freely write to/delete from.
- Access control for logs: they contain sensitive information; limit who reads them (overlaps with A01).
- Adequate retention: keep enough to investigate (per policy and regulation), but not indefinitely if they contain personal data.
- Synchronize clocks (NTP) across services: without consistent timestamps, forensic correlation becomes impossible.
Common Mistakes and Tips
- Not logging failures (failed login, 403, validation errors). Those are the attack signals.
- Logging sensitive data (passwords, tokens, PAN, full bodies). It turns the log into a breach.
- Logs in free text only. They make alerting hard; use a structured format.
- Logging but not alerting. Without detection/response, logs only serve the autopsy.
- Logs on the compromised server itself, unprotected. The attacker deletes them; centralize and protect integrity.
- Unsynchronized clocks. It breaks temporal correlation in forensics.
- Tip: define from the design stage (links to A04) which security events each component emits and which alert they trigger; logging isn't improvised afterward.
Exercises
Exercise 1. Classify what should and shouldn't be logged in a login attempt: email, entered password, result (success/failure), IP, issued session id, timestamp.
Exercise 2. The API logs every 403 (access denied) but no one looks at those logs. What detection opportunity is lost and how would you seize it?
Exercise 3. An attacker compromises a BazarNube container and deletes /var/log/app.log. Which two measures would have preserved the evidence?
Solutions
Solution 1. Log: the result (success/failure), the IP, the timestamp and a pseudonymized user identifier (userId or hash of the email). Don't log: the password (ever), the email in the clear if avoidable (better its hash) and the issued session id (it's a secret; leaking it enables session hijacking).
Solution 2. You lose early detection of escalation/IDOR and enumeration (A01): a burst of 403s from one account or IP indicates someone is probing unauthorized access. You seize it by creating an alert rule ("more than N 403s per user/IP in X minutes") that notifies the team, plus a trend dashboard to spot spikes.
Solution 3. (1) Centralize the logs in real time to an external system (SIEM/aggregator) the compromised container can't delete; (2) append-only/immutable storage with restricted access control. That way, even if the attacker deletes the local file, the evidence is already beyond their reach.
Conclusion
A09 closes the operational security loop: log the right events (and only those, without sensitive data), in a structured and correlatable format, to detect and respond in time, protecting the integrity of the logs themselves. In BazarNube we went from a mute system to one that emits security events with a reqId, pseudonymizes data, centralizes in a SIEM and fires actionable alerts.
Backlog entry — A09: structured logging of security events (login success/failure, 403, sensitive operations) with reqId; redaction of sensitive data and email hashing; centralization in a SIEM; alert rules for brute force and bursts of 403s; append-only logs with defined retention. These logs will be the basis of the incident case study in module 8 (08-03).
One category remains, the second novelty of 2021. When the server itself makes requests to URLs the attacker controls, we have a serious problem. The module's final lesson is A10:2021 – Server-Side Request Forgery (SSRF).
OWASP Course: Guidelines and Standards for Web Application Security
Module 1: Introduction to OWASP
Module 2: Main OWASP Projects
- OWASP Top Ten
- OWASP ASVS (Application Security Verification Standard)
- OWASP SAMM (Software Assurance Maturity Model)
- OWASP ZAP (Zed Attack Proxy)
- Other Key Projects: WSTG, Cheat Sheets and Dependency-Check
Module 3: OWASP Top Ten 2021 in Depth
- A01:2021 – Broken Access Control
- A02:2021 – Cryptographic Failures and Sensitive Data Exposure
- A03:2021 – Injection
- Cross-Site Scripting (XSS) in Depth
- A04:2021 – Insecure Design
- A05:2021 – Security Misconfiguration
- XML External Entities (XXE)
- A06:2021 – Vulnerable and Outdated Components
- A07:2021 – Identification and Authentication Failures
- A08:2021 – Software and Data Integrity Failures (Insecure Deserialization)
- A09:2021 – Security Logging and Monitoring Failures
- A10:2021 – Server-Side Request Forgery (SSRF)
Module 4: OWASP ASVS (Application Security Verification Standard)
Module 5: OWASP SAMM (Software Assurance Maturity Model)
Module 6: OWASP ZAP (Zed Attack Proxy)
- Introduction to ZAP
- Installation and Configuration
- Vulnerability Scanning
- Automating Security Testing
Module 7: Best Practices and Recommendations
- Secure Software Development Life Cycle (SDLC)
- Threat Modeling
- Integrating Security into DevOps (DevSecOps)
- Security Training and Awareness
- Additional Tools and Resources
Module 8: Practical Exercises and Case Studies
- Exercise 1: Identifying Vulnerabilities
- Exercise 2: Implementing Security Controls
- Case Study 1: Analyzing a Security Incident
- Case Study 2: Improving the Security of a Web Application
