SECURE-CODING
Authorized use only. Offensive reference for systems you own or are explicitly permitted to test. You are responsible for staying within the law.
Practical secure coding reference covering OWASP ASVS key requirements, CWE Top 25, and language-specific security tips.
OWASP ASVS KEY REQUIREMENTS#
V1 - Architecture, Design, and Threat Modeling: - Define security architecture early - Perform threat modeling (STRIDE, PASTA) - Document trust boundaries and data flows - Apply least privilege throughout V2 - Authentication: - Use multi-factor authentication for sensitive operations - Minimum password length: 8 characters (prefer 12+) - No password complexity rules (NIST 800-63B) - Check passwords against breached password lists - Implement account lockout or rate limiting - Use bcrypt/Argon2id/scrypt for password storage - Session timeout: 30 min idle, 12 hr absolute V3 - Session Management: - Generate session IDs with >= 128 bits of entropy - Regenerate session ID after authentication - Invalidate sessions on logout (server-side) - Set cookie flags: Secure, HttpOnly, SameSite=Strict - Implement idle and absolute session timeouts V4 - Access Control: - Enforce access control on every request (server-side) - Deny by default - Use RBAC or ABAC consistently - Validate that users can only access their own data - Log all access control failures V5 - Validation, Sanitization, and Encoding: - Validate all input on the server side - Use allowlists over denylists - Output encode for the correct context (HTML, JS, URL, CSS, SQL) - Validate file uploads (type, size, name) V6 - Stored Cryptography: - Use well-known, tested algorithms only - AES-256-GCM for symmetric encryption - RSA-2048+ or ECDSA P-256+ for asymmetric - Use proper key management - Never hardcode cryptographic keys V7 - Error Handling and Logging: - Never expose stack traces to users - Log security events (auth, access control, input validation failures) - Protect log integrity - Include who, what, when, where in log entries - Never log sensitive data (passwords, tokens, PII)
CWE TOP 25 WITH EXAMPLES#
CWE-787: Out-of-bounds Write
Vulnerable: memcpy(buf, input, strlen(input)); // no bounds check
Fixed: memcpy(buf, input, MIN(strlen(input), sizeof(buf)-1));
CWE-79: Cross-site Scripting (XSS)
Vulnerable: innerHTML = userInput;
Fixed: textContent = userInput; // or use encoding library
CWE-89: SQL Injection
Vulnerable: "SELECT * FROM users WHERE name='" + name + "'"
Fixed: PreparedStatement with parameterized query (see below)
CWE-416: Use After Free
Vulnerable: free(ptr); use(ptr);
Fixed: free(ptr); ptr = NULL;
CWE-78: OS Command Injection
Vulnerable: os.system("ping " + userInput)
Fixed: subprocess.run(["ping", userInput], shell=False)
CWE-20: Improper Input Validation
Vulnerable: Processing any input without validation
Fixed: Validate type, length, range, pattern before processing
CWE-125: Out-of-bounds Read
Vulnerable: return buffer[index]; // no bounds check
Fixed: if (index < bufferSize) return buffer[index];
CWE-22: Path Traversal
Vulnerable: open("/uploads/" + filename)
Fixed: Validate filename, use realpath(), check against base dir
CWE-352: Cross-Site Request Forgery
Vulnerable: Form without CSRF token
Fixed: Include and validate anti-CSRF token per session
CWE-434: Unrestricted Upload of Dangerous File Types
Vulnerable: Accept any uploaded file and serve it
Fixed: Validate type (magic bytes), rename, store outside webroot
INPUT VALIDATION PATTERNS#
Server-side validation rules:
1. Type checking - Is it the expected data type?
2. Range checking - Is it within acceptable bounds?
3. Length checking - Is it within acceptable length?
4. Pattern matching - Does it match expected format?
5. Allowlist - Is it in the set of allowed values?
Common validation patterns:
Email: ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
Phone: ^\+?[1-9]\d{1,14}$ (E.164)
UUID: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$
URL: Use URL parsing library, then validate scheme and host
Integer: Parse as integer, then check range
Date: Use date parsing library, then check range
Anti-patterns (DO NOT):
- Validate only on client side
- Use denylists (blocklists) for dangerous characters
- Use regex for HTML/XML parsing
- Trust Content-Type header for file type validation
- Trust file extension alone
OUTPUT ENCODING#
HTML Context: & -> & < -> < > -> > " -> " ' -> ' JavaScript Context: Encode all non-alphanumeric characters as \xHH or \uHHHH Better: use JSON.stringify() for data insertion URL Context: Encode using percent-encoding (encodeURIComponent in JS) CSS Context: Encode non-alphanumeric as \HHHHHH (six-digit hex) Libraries: Java: OWASP Java Encoder (org.owasp.encoder) Python: markupsafe.escape(), bleach JavaScript: DOMPurify (client), he (server) Go: html/template (auto-escapes) PHP: htmlspecialchars(string, ENT_QUOTES, 'UTF-8')
PARAMETERIZED QUERIES#
Java (JDBC):
String sql = "SELECT * FROM users WHERE email = ? AND status = ?";
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, email);
stmt.setString(2, status);
ResultSet rs = stmt.executeQuery();
Python (psycopg2):
cursor.execute("SELECT * FROM users WHERE email = %s AND status = %s",
(email, status))
Python (SQLAlchemy):
result = session.query(User).filter(User.email == email).all()
JavaScript (Node.js pg):
const result = await pool.query(
'SELECT * FROM users WHERE email = $1 AND status = $2',
[email, status]
);
Go (database/sql):
rows, err := db.Query("SELECT * FROM users WHERE email = ? AND status = ?",
email, status)
C# (ADO.NET):
var cmd = new SqlCommand("SELECT * FROM users WHERE email = @email", conn);
cmd.Parameters.AddWithValue("@email", email);
PHP (PDO):
$stmt = $pdo->prepare("SELECT * FROM users WHERE email = :email");
$stmt->execute(['email' => $email]);
ORM best practices:
- Use ORM query builders (they parameterize automatically)
- Never concatenate user input into raw SQL
- Be cautious with raw query methods even in ORMs
SECURE SESSION MANAGEMENT#
Session ID generation: - Use cryptographically secure random generator - Minimum 128 bits of entropy - Use framework's built-in session management Cookie configuration: Set-Cookie: sessionId=<value>; Secure; HttpOnly; SameSite=Strict; Path=/; Max-Age=1800 Session lifecycle: 1. Generate new session ID on login (prevent fixation) 2. Validate session on every request 3. Implement idle timeout (15-30 minutes) 4. Implement absolute timeout (8-12 hours) 5. Invalidate session server-side on logout 6. Regenerate session on privilege change Token-based (JWT) considerations: - Use short expiration times (15-60 minutes) - Implement refresh token rotation - Store refresh tokens securely (HttpOnly cookie) - Validate all claims (iss, aud, exp, nbf) - Use strong signing algorithms (RS256, ES256) - Never use "none" algorithm - Include token in Authorization header, not URL
ERROR HANDLING#
Principles:
- Catch specific exceptions, not generic ones
- Log detailed errors server-side
- Return generic messages to users
- Never expose stack traces, SQL errors, or internal paths
- Fail securely (deny access on error)
Bad:
catch (Exception e) {
response.send("Error: " + e.getMessage() + "\n" + e.getStackTrace());
}
Good:
catch (SQLException e) {
logger.error("Database error in getUserProfile: {}", e.getMessage(), e);
response.status(500).send("An internal error occurred. Reference: " + errorId);
}
Error response format (API):
{
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred",
"reference": "ERR-20260319-ABC123"
}
}
FILE UPLOAD SECURITY#
Validation checklist: [ ] Validate file type by magic bytes (not just extension) [ ] Enforce maximum file size [ ] Generate new random filename (never use user-provided name) [ ] Store outside web root [ ] Set Content-Disposition: attachment on download [ ] Scan with antivirus [ ] Strip metadata (EXIF, etc.) [ ] Validate image dimensions (prevent pixel flood DoS) Magic bytes check: JPEG: FF D8 FF PNG: 89 50 4E 47 PDF: 25 50 44 46 GIF: 47 49 46 38 ZIP: 50 4B 03 04 Storage: - Store files outside document root - Use a separate domain for user-uploaded content - Serve through a handler that sets proper Content-Type - Never execute uploaded files - Consider using object storage (S3, GCS) with signed URLs
LANGUAGE-SPECIFIC TIPS#
PYTHON:
# Use secrets module for crypto random
import secrets
token = secrets.token_urlsafe(32)
# Avoid eval/exec
# NEVER: eval(user_input)
# Use ast.literal_eval for parsing literals safely
# Use subprocess safely
import subprocess
subprocess.run(["ls", "-la", path], shell=False, check=True)
# NEVER: os.system("ls " + path)
# YAML safe loading
import yaml
data = yaml.safe_load(content) # NOT yaml.load(content)
# Template injection prevention
# Use autoescape in Jinja2
env = Environment(autoescape=True)
# Pickle deserialization danger
# NEVER unpickle untrusted data
# Use JSON or MessagePack instead
# Django security settings
DEBUG = False
SECURE_SSL_REDIRECT = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
X_FRAME_OPTIONS = 'DENY'
JAVA:
// Use try-with-resources
try (Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, userInput);
try (ResultSet rs = ps.executeQuery()) { ... }
}
// XML parsing - prevent XXE
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
// Deserialization safety
// Avoid Java native deserialization of untrusted data
// Use ObjectInputFilter (Java 9+)
// Prefer JSON with Jackson (configure safely)
// Use Security Manager or modern alternatives
// Validate all redirect URLs against allowlist
// Spring Security: enable CSRF, CORS properly
// Use @Valid for input validation with Bean Validation
JAVASCRIPT (NODE.JS):
// Avoid eval and Function constructor
// NEVER: eval(userInput)
// NEVER: new Function(userInput)
// Use parameterized queries (see above)
// Helmet.js for Express security headers
const helmet = require('helmet');
app.use(helmet());
// Rate limiting
const rateLimit = require('express-rate-limit');
app.use(rateLimit({ windowMs: 15*60*1000, max: 100 }));
// DOMPurify for HTML sanitization (client)
const clean = DOMPurify.sanitize(dirty);
// Avoid prototype pollution
// Use Object.create(null) for dictionary objects
// Validate JSON keys before assignment
// Use Map instead of plain objects for user-keyed data
// npm audit for dependency vulnerabilities
npm audit
npm audit fix
// CSP headers
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:"],
}
}));
GO:
// html/template auto-escapes (use instead of text/template)
tmpl := template.Must(template.ParseFiles("page.html"))
tmpl.Execute(w, data)
// SQL parameterization
rows, err := db.Query("SELECT * FROM users WHERE id = $1", userID)
// Avoid fmt.Sprintf for SQL
// NEVER: db.Query(fmt.Sprintf("SELECT * FROM users WHERE id = '%s'", id))
// Use crypto/rand (not math/rand) for security
import "crypto/rand"
token := make([]byte, 32)
_, err := rand.Read(token)
// Input validation with custom validators
// Use validator package: github.com/go-playground/validator
// HTTP security
// Set timeouts on http.Server
srv := &http.Server{
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
// Use filepath.Clean and filepath.Abs for path validation
cleanPath := filepath.Clean(userPath)
if !strings.HasPrefix(cleanPath, baseDir) {
// path traversal attempt
}
SECURITY HEADERS#
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' Strict-Transport-Security: max-age=31536000; includeSubDomains; preload X-Content-Type-Options: nosniff X-Frame-Options: DENY X-XSS-Protection: 0 (deprecated, rely on CSP instead) Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: camera=(), microphone=(), geolocation=() Cache-Control: no-store (for sensitive pages)
REFERENCES#
- OWASP ASVS: https://owasp.org/www-project-application-security-verification-standard/ - CWE Top 25: https://cwe.mitre.org/top25/ - OWASP Cheat Sheet Series: https://cheatsheetseries.owasp.org/ - NIST SP 800-63B (Digital Identity): https://pages.nist.gov/800-63-3/ - SANS Secure Coding Guidelines: https://www.sans.org/