Secure Python Development

Security best practices for Python applications including Django, Flask, FastAPI, and data science workflows.

Overview

Python's dynamic nature provides flexibility but requires careful attention to security. This guide covers critical practices for secure Python development.

Security Checklist

  • Never use eval(), exec(), or compile() with user input
  • Use parameterized queries for all database operations
  • Avoid pickle and yaml.load() with untrusted data
  • Enable Django security middleware
  • Use HTTPS and set secure cookie flags
  • Validate and sanitize all user input
  • Keep dependencies updated with pip-audit
  • Use virtual environments to isolate dependencies

Preventing Injection

SQL injection and command injection are critical vulnerabilities. Always use parameterized queries and avoid shell execution with user input.

Python
1# SQL Injection Prevention
2# BAD: String formatting
3cursor.execute(f"SELECT * FROM users WHERE id = '{user_id}'")
4
5# GOOD: Parameterized query
6cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
7
8# Command Injection Prevention
9# BAD: os.system with user input
10os.system(f"convert {filename} output.png")
11
12# GOOD: subprocess with argument list
13import subprocess
14import shlex
15
16# Validate filename first
17if not filename.replace('.', '').replace('_', '').isalnum():
18 raise ValueError("Invalid filename")
19
20subprocess.run(['convert', filename, 'output.png'], check=True)

Safe Serialization

Never Unpickle Untrusted Data

Pickle can execute arbitrary code during deserialization. Never use it with data from untrusted sources.
Python
1# BAD: Pickle with untrusted data
2import pickle
3data = pickle.loads(user_input) # RCE vulnerability!
4
5# GOOD: Use JSON for data exchange
6import json
7data = json.loads(user_input) # Safe
8
9# YAML: Use safe_load
10import yaml
11# BAD
12data = yaml.load(user_input, Loader=yaml.FullLoader) # Dangerous
13
14# GOOD
15data = yaml.safe_load(user_input) # Safe

Django Security

Django provides built-in security features. Ensure they are properly configured.

Python
1# settings.py security configuration
2
3# SECURITY WARNING: don't run with debug turned on in production!
4DEBUG = False
5
6# HTTPS settings
7SECURE_SSL_REDIRECT = True
8SECURE_HSTS_SECONDS = 31536000
9SECURE_HSTS_INCLUDE_SUBDOMAINS = True
10SECURE_HSTS_PRELOAD = True
11
12# Cookie security
13SESSION_COOKIE_SECURE = True
14CSRF_COOKIE_SECURE = True
15SESSION_COOKIE_HTTPONLY = True
16
17# Content security
18SECURE_CONTENT_TYPE_NOSNIFF = True
19X_FRAME_OPTIONS = 'DENY'
20
21# Use the ORM, not raw SQL
22# BAD
23User.objects.raw(f"SELECT * FROM users WHERE name = '{name}'")
24
25# GOOD
26User.objects.filter(name=name)

Flask Security

Flask requires explicit security configuration. Use Flask-Talisman for security headers and Flask-WTF for CSRF protection.

Python
1from flask import Flask
2from flask_talisman import Talisman
3from flask_wtf.csrf import CSRFProtect
4
5app = Flask(__name__)
6app.config['SECRET_KEY'] = os.environ['SECRET_KEY']
7
8# Security headers
9Talisman(app,
10 force_https=True,
11 strict_transport_security=True,
12 content_security_policy={
13 'default-src': "'self'",
14 'script-src': "'self'",
15 }
16)
17
18# CSRF protection
19csrf = CSRFProtect(app)
20
21# Never use debug in production
22if __name__ == '__main__':
23 app.run(debug=os.environ.get('FLASK_DEBUG', False))

Dependency Security

Bash
1# Install pip-audit for vulnerability scanning
2pip install pip-audit
3
4# Scan dependencies
5pip-audit
6
7# Use Bloodhound for deep analysis
8bloodhound scan --mode dependencies
9
10# Pin dependencies in requirements.txt
11pip freeze > requirements.txt
12
13# Use virtual environments
14python -m venv venv
15source venv/bin/activate # Linux/Mac
16venv\Scripts\activate # Windows

Integrate Security in CI/CD

Run Bloodhound and pip-audit in your CI/CD pipeline to catch vulnerabilities before deployment.