Security Essentials & Best Practices
Security best practices, OWASP Top 10, secure coding practices, and security testing tools.
OWASP Top 10 (2021)
A01: Broken Access Control
Vulnerability
1# β Insecure Direct Object Reference (IDOR)
2@app.route('/api/users/<user_id>')
3def get_user(user_id):
4 user = db.query(f"SELECT * FROM users WHERE id = {user_id}")
5 return jsonify(user)
6
7# Attacker can access any user: /api/users/123
Mitigation
1# β
Check authorization
2@app.route('/api/users/<user_id>')
3@login_required
4def get_user(user_id):
5 current_user = get_current_user()
6
7 # Check if user can access this resource
8 if current_user.id != user_id and not current_user.is_admin:
9 abort(403)
10
11 user = db.query("SELECT * FROM users WHERE id = ?", [user_id])
12 return jsonify(user)
13
14# β
Use UUIDs instead of sequential IDs
15import uuid
16
17user_id = str(uuid.uuid4()) # e.g., '550e8400-e29b-41d4-a716-446655440000'
A02: Cryptographic Failures
Vulnerability
1# β Storing passwords in plain text
2user.password = request.form['password']
3db.save(user)
4
5# β Using weak hashing
6import hashlib
7user.password = hashlib.md5(password.encode()).hexdigest()
Mitigation
1# β
Use bcrypt for password hashing
2import bcrypt
3
4# Hash password
5password = "user_password"
6hashed = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt())
7
8# Verify password
9if bcrypt.checkpw(password.encode('utf-8'), hashed):
10 print("Password matches")
11
12# β
Use strong encryption for sensitive data
13from cryptography.fernet import Fernet
14
15# Generate key
16key = Fernet.generate_key()
17cipher = Fernet(key)
18
19# Encrypt
20encrypted = cipher.encrypt(b"sensitive data")
21
22# Decrypt
23decrypted = cipher.decrypt(encrypted)
A03: Injection
SQL Injection
1# β Vulnerable to SQL injection
2username = request.form['username']
3query = f"SELECT * FROM users WHERE username = '{username}'"
4db.execute(query)
5
6# Attack: username = "admin' OR '1'='1"
7# Result: SELECT * FROM users WHERE username = 'admin' OR '1'='1'
1# β
Use parameterized queries
2username = request.form['username']
3query = "SELECT * FROM users WHERE username = ?"
4db.execute(query, [username])
5
6# β
Use ORM
7from sqlalchemy import select
8
9stmt = select(User).where(User.username == username)
10result = session.execute(stmt)
Command Injection
1# β Vulnerable to command injection
2filename = request.form['filename']
3os.system(f'cat {filename}')
4
5# Attack: filename = "file.txt; rm -rf /"
1# β
Use safe alternatives
2import subprocess
3
4filename = request.form['filename']
5# Validate filename
6if not re.match(r'^[a-zA-Z0-9_.-]+$', filename):
7 abort(400)
8
9# Use subprocess with list
10result = subprocess.run(['cat', filename], capture_output=True)
XSS (Cross-Site Scripting)
1# β Vulnerable to XSS
2@app.route('/search')
3def search():
4 query = request.args.get('q')
5 return f'<h1>Results for: {query}</h1>'
6
7# Attack: /search?q=<script>alert('XSS')</script>
1# β
Escape user input
2from markupsafe import escape
3
4@app.route('/search')
5def search():
6 query = request.args.get('q')
7 return f'<h1>Results for: {escape(query)}</h1>'
8
9# β
Use templating engines (auto-escape)
10return render_template('search.html', query=query)
11
12# β
Content Security Policy
13@app.after_request
14def set_csp(response):
15 response.headers['Content-Security-Policy'] = "default-src 'self'"
16 return response
A04: Insecure Design
Mitigation
1# β
Implement rate limiting
2from flask_limiter import Limiter
3
4limiter = Limiter(
5 app,
6 key_func=lambda: request.remote_addr,
7 default_limits=["200 per day", "50 per hour"]
8)
9
10@app.route('/api/login')
11@limiter.limit("5 per minute")
12def login():
13 # Login logic
14 pass
15
16# β
Implement account lockout
17class User:
18 failed_login_attempts = 0
19 locked_until = None
20
21 def check_login(self, password):
22 if self.locked_until and datetime.now() < self.locked_until:
23 raise AccountLockedException()
24
25 if self.verify_password(password):
26 self.failed_login_attempts = 0
27 return True
28 else:
29 self.failed_login_attempts += 1
30 if self.failed_login_attempts >= 5:
31 self.locked_until = datetime.now() + timedelta(minutes=15)
32 return False
A05: Security Misconfiguration
Checklist
1# β
Disable debug mode in production
2DEBUG = False
3
4# β
Remove default credentials
5# Change default admin/admin, root/root, etc.
6
7# β
Disable directory listing
8# Apache: Options -Indexes
9# Nginx: autoindex off;
10
11# β
Remove unnecessary services
12sudo systemctl disable <service>
13
14# β
Keep software updated
15sudo apt update && sudo apt upgrade
16
17# β
Configure HTTPS
18# Use Let's Encrypt
19sudo certbot --nginx -d example.com
20
21# β
Set secure headers
22@app.after_request
23def set_security_headers(response):
24 response.headers['X-Content-Type-Options'] = 'nosniff'
25 response.headers['X-Frame-Options'] = 'DENY'
26 response.headers['X-XSS-Protection'] = '1; mode=block'
27 response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
28 return response
A06: Vulnerable and Outdated Components
Tools
1# Python
2pip install safety
3safety check
4
5# Node.js
6npm audit
7npm audit fix
8
9# Go
10go list -json -m all | nancy sleuth
11
12# Docker
13docker scan myimage:latest
14
15# Snyk
16npm install -g snyk
17snyk test
A07: Identification and Authentication Failures
Best Practices
1# β
Implement MFA
2from pyotp import TOTP
3
4# Generate secret
5secret = pyotp.random_base32()
6
7# Verify TOTP
8totp = TOTP(secret)
9if totp.verify(user_code):
10 print("Valid code")
11
12# β
Secure password reset
13import secrets
14
15def generate_reset_token():
16 return secrets.token_urlsafe(32)
17
18def send_reset_email(user):
19 token = generate_reset_token()
20 # Store token with expiration
21 user.reset_token = token
22 user.reset_token_expires = datetime.now() + timedelta(hours=1)
23 # Send email with token
24 send_email(user.email, f"Reset link: /reset?token={token}")
25
26# β
Implement session timeout
27@app.before_request
28def check_session_timeout():
29 if 'last_activity' in session:
30 last_activity = session['last_activity']
31 if datetime.now() - last_activity > timedelta(minutes=30):
32 session.clear()
33 return redirect('/login')
34 session['last_activity'] = datetime.now()
A08: Software and Data Integrity Failures
Mitigation
1# β
Verify file uploads
2ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
3
4def allowed_file(filename):
5 return '.' in filename and \
6 filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
7
8@app.route('/upload', methods=['POST'])
9def upload_file():
10 file = request.files['file']
11
12 if not allowed_file(file.filename):
13 abort(400)
14
15 # Verify file content (not just extension)
16 import magic
17 mime = magic.from_buffer(file.read(1024), mime=True)
18 if mime not in ['image/png', 'image/jpeg', 'image/gif']:
19 abort(400)
20
21 # Save with secure filename
22 from werkzeug.utils import secure_filename
23 filename = secure_filename(file.filename)
24 file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
25
26# β
Use Subresource Integrity (SRI)
27<script src="https://cdn.example.com/lib.js"
28 integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
29 crossorigin="anonymous"></script>
A09: Security Logging and Monitoring Failures
Implementation
1import logging
2from logging.handlers import RotatingFileHandler
3
4# Configure logging
5handler = RotatingFileHandler('security.log', maxBytes=10000000, backupCount=5)
6handler.setLevel(logging.INFO)
7
8formatter = logging.Formatter(
9 '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
10)
11handler.setFormatter(formatter)
12
13security_logger = logging.getLogger('security')
14security_logger.addHandler(handler)
15
16# Log security events
17@app.route('/login', methods=['POST'])
18def login():
19 username = request.form['username']
20 password = request.form['password']
21
22 user = User.query.filter_by(username=username).first()
23
24 if user and user.verify_password(password):
25 security_logger.info(f"Successful login: {username} from {request.remote_addr}")
26 return redirect('/dashboard')
27 else:
28 security_logger.warning(f"Failed login attempt: {username} from {request.remote_addr}")
29 return redirect('/login')
30
31# Monitor for suspicious activity
32def detect_brute_force(username, ip_address):
33 """Detect brute force attempts"""
34 recent_attempts = FailedLogin.query.filter(
35 FailedLogin.username == username,
36 FailedLogin.ip_address == ip_address,
37 FailedLogin.timestamp > datetime.now() - timedelta(minutes=5)
38 ).count()
39
40 if recent_attempts > 5:
41 security_logger.critical(f"Brute force detected: {username} from {ip_address}")
42 # Send alert
43 send_alert(f"Brute force attack detected from {ip_address}")
A10: Server-Side Request Forgery (SSRF)
Vulnerability
1# β Vulnerable to SSRF
2@app.route('/fetch')
3def fetch_url():
4 url = request.args.get('url')
5 response = requests.get(url)
6 return response.content
7
8# Attack: /fetch?url=http://localhost:6379/
9# Can access internal services
Mitigation
1# β
Whitelist allowed domains
2ALLOWED_DOMAINS = ['api.example.com', 'cdn.example.com']
3
4def is_safe_url(url):
5 from urllib.parse import urlparse
6 parsed = urlparse(url)
7 return parsed.netloc in ALLOWED_DOMAINS
8
9@app.route('/fetch')
10def fetch_url():
11 url = request.args.get('url')
12
13 if not is_safe_url(url):
14 abort(400)
15
16 response = requests.get(url, timeout=5)
17 return response.content
18
19# β
Block private IP ranges
20import ipaddress
21
22def is_private_ip(hostname):
23 try:
24 ip = ipaddress.ip_address(hostname)
25 return ip.is_private or ip.is_loopback
26 except ValueError:
27 return False
Security Testing Tools
Static Analysis
1# Python - Bandit
2pip install bandit
3bandit -r ./myproject
4
5# JavaScript - ESLint Security
6npm install --save-dev eslint-plugin-security
7eslint --plugin security .
8
9# Go - Gosec
10go install github.com/securego/gosec/v2/cmd/gosec@latest
11gosec ./...
Dynamic Analysis
1# OWASP ZAP
2docker run -t owasp/zap2docker-stable zap-baseline.py -t https://example.com
3
4# Burp Suite
5# GUI tool for web application security testing
6
7# Nikto
8nikto -h https://example.com
Dependency Scanning
1# Python
2pip install safety
3safety check
4
5# Node.js
6npm audit
7
8# Snyk (multi-language)
9snyk test
Security Checklist
1β‘ Use HTTPS everywhere
2β‘ Implement proper authentication
3β‘ Use strong password hashing (bcrypt, Argon2)
4β‘ Validate and sanitize all input
5β‘ Use parameterized queries (prevent SQL injection)
6β‘ Implement CSRF protection
7β‘ Set secure HTTP headers
8β‘ Implement rate limiting
9β‘ Log security events
10β‘ Keep dependencies updated
11β‘ Use environment variables for secrets
12β‘ Implement proper error handling (don't leak info)
13β‘ Use Content Security Policy
14β‘ Implement account lockout
15β‘ Use secure session management
16β‘ Validate file uploads
17β‘ Implement proper authorization checks
18β‘ Use security scanning tools
19β‘ Conduct regular security audits
20β‘ Have an incident response plan
Related Snippets
- DNS Fundamentals & Configuration
DNS fundamentals and practical configuration for common services like Gmail and β¦ - iftop - Network Bandwidth Monitor
Real-time network bandwidth monitoring with iftop. Basic Usage Monitor Default β¦ - iperf & iperf3 Network Testing
Network bandwidth testing with iperf and iperf3. Understand differences and β¦ - NATS Setup with JWT Authorization
NATS server setup and JWT-based authorization cheatsheet - Performance Measurement Tools
Essential tools for measuring network and computer performance. Quick reference β¦ - Serial Port Sniffing
Tools and techniques for capturing and analyzing serial port communication β¦ - tcpdump - Packet Capture
Packet capture and analysis with tcpdump. Essential tool for network debugging β¦ - WireGuard VPN Setup
WireGuard VPN setup with port forwarding and tunneling. Modern, fast, and secure β¦