9.3.1. Secure Coding Principles and OWASP Top 10
💡 First Principle: Secure coding principles are defensive defaults — assumptions that every input is hostile, every error path matters, and every access must be verified. When these principles are applied consistently, entire vulnerability classes are eliminated structurally rather than discovered and patched individually. The cost difference is orders of magnitude: preventing SQL injection by using parameterized queries everywhere is cheaper than finding and fixing SQL injection bugs one at a time across thousands of code paths.
OWASP Top 10 (2021) — the vulnerability classes that matter most:
| Rank | Category | Root Cause | Prevention |
|---|---|---|---|
| A01 | Broken Access Control | Missing or inconsistent authorization checks | Deny by default; enforce at server side; verify on every request |
| A02 | Cryptographic Failures | Weak algorithms, poor key management, data exposure | Use current algorithms (AES-256, SHA-256+); manage keys properly; encrypt data at rest and in transit |
| A03 | Injection | Untrusted input interpreted as code | Parameterized queries (SQL); output encoding (XSS); input validation (allowlist) |
| A04 | Insecure Design | Missing threat model; no security architecture | Threat modeling in design phase; secure design patterns; abuse case analysis |
| A05 | Security Misconfiguration | Default credentials; unnecessary features enabled; verbose errors | Hardened baselines; automated configuration scanning; minimal installation |
| A06 | Vulnerable Components | Using libraries with known CVEs | SCA scanning; SBOM maintenance; dependency update process |
| A07 | Authentication Failures | Weak passwords; missing MFA; session mismanagement | MFA; credential stuffing protection; secure session handling |
| A08 | Data Integrity Failures | Untrusted deserialization; unsigned updates | Input validation on serialized data; signed and verified software updates |
| A09 | Logging Failures | Insufficient logging; logs not monitored | Log security-relevant events; protect log integrity; integrate with SIEM |
| A10 | SSRF | Server makes requests to attacker-controlled URLs | Validate and sanitize all URLs; allowlist permitted destinations; segment network |
Core secure coding principles:
- Input validation — Validate all input on the server side. Allowlist validation (define what IS allowed) is stronger than denylist validation (define what IS NOT allowed) because denylist approaches cannot anticipate every possible malicious input. Validate data type, length, range, and format.
- Output encoding — Encode output based on the context where it will be rendered (HTML encoding for web pages, URL encoding for query parameters, JavaScript encoding for script contexts). Output encoding prevents XSS by ensuring user-supplied data is treated as data, not executable code.
- Parameterized queries — The definitive defense against SQL injection. Parameterized queries (prepared statements) separate SQL code from data — the database engine treats user input as a literal value, never as executable SQL. Input filtering alone is insufficient because filter bypass techniques are well-documented.
- Fail secure — When an error occurs, the system should deny access rather than grant it. A firewall that fails open allows all traffic during a malfunction; a firewall that fails closed blocks all traffic. For security controls, fail closed is the correct default.
- Secure defaults — Applications should ship with the most secure configuration possible. Features that reduce security (debug mode, verbose error messages, default admin accounts) should be disabled by default and require explicit activation.
- Least privilege in code — Application components should run with the minimum permissions required. A web application should not run as root/admin. Database connections should use accounts with only the permissions needed (SELECT for read operations, not full DBA access).
Memory safety vulnerabilities:
Buffer overflows remain relevant for the CISSP despite being a lower-level vulnerability class:
| Vulnerability | Mechanism | Prevention |
|---|---|---|
| Buffer overflow | Input exceeds allocated memory; overwrites adjacent data/code | Memory-safe languages (Rust, Go, Java); bounds checking; ASLR; DEP/NX; stack canaries |
| Integer overflow | Arithmetic exceeds data type capacity; wraps to unexpected value | Safe integer libraries; range validation before arithmetic operations |
| Format string | User input used directly in format functions (printf) | Never use user input as format strings; use fixed format strings with arguments |
⚠️ Exam Trap: SQL injection is prevented by parameterized queries — not by input filtering alone. Input filtering (stripping single quotes, escaping special characters) can be bypassed with encoding techniques, alternative syntax, or second-order injection. The exam tests whether you know the structural defense (parameterized queries) versus the brittle defense (input filtering).
Reflection Question: A code review reveals that a web application constructs SQL queries by concatenating user input directly into the query string. The developer argues this is safe because the application strips single quotes from all input before concatenation. Explain why this defense is insufficient, provide a specific bypass technique, and describe the correct architectural fix that eliminates SQL injection structurally.