Security vulnerability detection and secure coding practices
This skill provides expert knowledge on identifying security vulnerabilities and implementing secure coding practices.
SQL Injection
# Vulnerable
query = f"SELECT * FROM users WHERE email = '{user_input}'"
# Secure: Use parameterized queries
query = "SELECT * FROM users WHERE email = ?"
cursor.execute(query, (user_input,))
Command Injection
# Vulnerable
os.system(f"ping {user_input}")
# Secure: Validate input and use safe APIs
import subprocess
subprocess.run(["ping", "-c", "1", validated_host], check=True)
NoSQL Injection
// Vulnerable
db.users.find({ email: req.body.email })
// Secure: Validate input type
const email = String(req.body.email);
db.users.find({ email: email })
Password Storage
# Vulnerable: Plain text or MD5
password = "user_password"
# Secure: Use bcrypt, Argon2, or PBKDF2
import bcrypt
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt())
Session Management
# Secure session configuration
SESSION_COOKIE_SECURE = True # HTTPS only
SESSION_COOKIE_HTTPONLY = True # No JavaScript access
SESSION_COOKIE_SAMESITE = 'Strict'
SESSION_TIMEOUT = 30 * 60 # 30 minutes
Encryption in Transit
# Always use HTTPS/TLS
# Enforce HSTS headers
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
Encryption at Rest
from cryptography.fernet import Fernet
# Encrypt sensitive data
cipher = Fernet(encryption_key)
encrypted_data = cipher.encrypt(sensitive_data.encode())
# Never log sensitive information
logger.info(f"User logged in") # Don't log passwords, tokens, etc.
# Vulnerable
import xml.etree.ElementTree as ET
tree = ET.parse(user_file)
# Secure: Disable external entity processing
from defusedxml import ElementTree as ET
tree = ET.parse(user_file)
# Vulnerable: Insecure Direct Object Reference (IDOR)
@app.route('/users/<user_id>')
def get_user(user_id):
return User.get(user_id) # Any user can access any user_id
# Secure: Check authorization
@app.route('/users/<user_id>')
@login_required
def get_user(user_id):
if current_user.id != user_id and not current_user.is_admin:
abort(403)
return User.get(user_id)
Checklist:
# Development
DEBUG = True
SHOW_ERRORS = True
# Production
DEBUG = False
SHOW_ERRORS = False
ALLOWED_HOSTS = ['yourdomain.com']
Stored XSS
# Vulnerable: Direct HTML output
return f"<div>Welcome, {username}</div>"
# Secure: Escape HTML
from html import escape
return f"<div>Welcome, {escape(username)}</div>"
DOM-based XSS
// Vulnerable
element.innerHTML = userInput;
// Secure
element.textContent = userInput;
Content Security Policy (CSP)
response.headers['Content-Security-Policy'] = (
"default-src 'self'; "
"script-src 'self' 'unsafe-inline'; "
"style-src 'self' 'unsafe-inline'"
)
# Vulnerable: pickle can execute arbitrary code
import pickle
data = pickle.loads(untrusted_data)
# Secure: Use JSON for untrusted data
import json
data = json.loads(untrusted_data)
Best Practices:
# Regularly update dependencies
pip list --outdated
npm audit
# Use dependency scanning tools
pip-audit
npm audit fix
# Pin versions in production
pip freeze > requirements.txt
npm ci # Instead of npm install
import logging
# Log security events
logger.warning(f"Failed login attempt for user: {email} from IP: {ip_address}")
logger.critical(f"Potential SQL injection detected: {suspicious_input}")
# What to log:
# - Authentication attempts (success/failure)
# - Authorization failures
# - Input validation failures
# - Application errors
# - Administrative actions
# What NOT to log:
# - Passwords, tokens, session IDs
# - Credit card numbers, PII
# - Encryption keys
# Vulnerable: Denylist (easily bypassed)
if '<script>' not in user_input:
process(user_input)
# Secure: Allowlist
import re
if re.match(r'^[a-zA-Z0-9_-]+$', user_input):
process(user_input)