Diagrams: Security Basics¶
OWASP Top Risks for Python Developers¶
The most common web security vulnerabilities, ranked by how often they appear in Python projects.
flowchart TD
subgraph INJECTION ["Injection Attacks"]
SQL["SQL Injection<br/>User input in queries<br/>Fix: parameterized queries"]
CMD["Command Injection<br/>User input in shell calls<br/>Fix: subprocess with list args"]
end
subgraph XSS_CSRF ["Cross-Site Attacks"]
XSS["XSS<br/>Script in user content<br/>Fix: auto-escaping templates"]
CSRF["CSRF<br/>Forged form submission<br/>Fix: CSRF tokens"]
end
subgraph AUTH_ISSUES ["Authentication Flaws"]
WEAK["Weak Passwords<br/>No complexity rules<br/>Fix: bcrypt/argon2 hashing"]
SESSION["Session Hijacking<br/>Stolen cookies<br/>Fix: HttpOnly, Secure flags"]
end
subgraph DATA_EXPOSURE ["Data Exposure"]
SECRETS["Hardcoded Secrets<br/>API keys in source code<br/>Fix: environment variables"]
PATH["Path Traversal<br/>../../etc/passwd<br/>Fix: resolve() + is_relative_to()"]
LOGGING["Sensitive Data in Logs<br/>Passwords in log output<br/>Fix: never log secrets"]
end
subgraph SUPPLY ["Supply Chain"]
DEPS["Vulnerable Dependencies<br/>Outdated packages<br/>Fix: pip audit regularly"]
end
style INJECTION fill:#ff6b6b,stroke:#c92a2a,color:#fff
style XSS_CSRF fill:#ff922b,stroke:#e8590c,color:#fff
style AUTH_ISSUES fill:#ffd43b,stroke:#f59f00,color:#000
style DATA_EXPOSURE fill:#4a9eff,stroke:#2670c2,color:#fff
style SUPPLY fill:#cc5de8,stroke:#9c36b5,color:#fff
Input Sanitization Flow¶
Every piece of user input must be validated before it touches your application logic, database, or output.
flowchart TD
INPUT["Raw User Input<br/>(form, URL, API body, file)"] --> VALIDATE{"Step 1: Validate<br/>Correct type and format?"}
VALIDATE -->|"Invalid"| REJECT["Reject with clear error<br/>400 Bad Request"]
VALIDATE -->|"Valid"| SANITIZE["Step 2: Sanitize<br/>Strip dangerous characters"]
SANITIZE --> CONTEXT{"Where is this<br/>data going?"}
CONTEXT -->|"Database"| DB_SAFE["Use parameterized queries<br/>cursor.execute(sql, (value,))"]
CONTEXT -->|"HTML output"| HTML_SAFE["Auto-escape template<br/>Jinja2 escapes by default"]
CONTEXT -->|"File path"| PATH_SAFE["Resolve and check<br/>path.is_relative_to(base)"]
CONTEXT -->|"Shell command"| CMD_SAFE["Use subprocess with list<br/>Never pass raw strings"]
CONTEXT -->|"JSON response"| JSON_SAFE["Serialize with json.dumps<br/>Auto-escapes special chars"]
DB_SAFE --> SAFE["Data is safe"]
HTML_SAFE --> SAFE
PATH_SAFE --> SAFE
CMD_SAFE --> SAFE
JSON_SAFE --> SAFE
style INPUT fill:#ff6b6b,stroke:#c92a2a,color:#fff
style REJECT fill:#ff6b6b,stroke:#c92a2a,color:#fff
style VALIDATE fill:#ffd43b,stroke:#f59f00,color:#000
style SANITIZE fill:#ff922b,stroke:#e8590c,color:#fff
style SAFE fill:#51cf66,stroke:#27ae60,color:#fff
Authentication vs Authorization¶
Authentication proves WHO you are. Authorization determines WHAT you can do. They are separate steps.
sequenceDiagram
participant User as User
participant App as Application
participant AuthN as Authentication<br/>(Who are you?)
participant AuthZ as Authorization<br/>(What can you do?)
participant Resource as Protected Resource
User->>App: POST /login<br/>username + password
App->>AuthN: Verify credentials
Note over AuthN: Check password hash<br/>with bcrypt.checkpw()
AuthN-->>App: Identity confirmed: alice (role: editor)
Note over App: Create session/JWT token<br/>Include user ID and role
App-->>User: 200 OK + token
User->>App: GET /admin/users<br/>Authorization: Bearer token
App->>AuthN: Verify token is valid
AuthN-->>App: Token valid, user = alice
App->>AuthZ: Can alice access /admin/users?
Note over AuthZ: Check role: editor<br/>Required: admin
AuthZ-->>App: DENIED
App-->>User: 403 Forbidden<br/>You are logged in (authenticated)<br/>but not allowed (not authorized)
User->>App: GET /articles<br/>Authorization: Bearer token
App->>AuthN: Verify token
AuthN-->>App: Token valid, user = alice
App->>AuthZ: Can alice access /articles?
Note over AuthZ: Check role: editor<br/>Required: editor or admin
AuthZ-->>App: ALLOWED
App->>Resource: Fetch articles
Resource-->>App: Article data
App-->>User: 200 OK + articles
Secrets Management Decision Tree¶
Where and how to store secrets depends on your environment.
flowchart TD
START["Where to store secrets?"] --> ENV{"What environment?"}
ENV -->|"Local development"| DOTENV[".env file<br/>+ python-dotenv<br/>+ add to .gitignore"]
ENV -->|"CI/CD pipeline"| CI_SECRETS["Pipeline secrets<br/>GitHub Secrets<br/>GitLab CI Variables"]
ENV -->|"Production server"| PROD{"Scale?"}
PROD -->|"Small/simple"| ENV_VARS["Environment variables<br/>Set in hosting platform<br/>(Railway, Heroku, etc.)"]
PROD -->|"Large/enterprise"| VAULT["Secrets manager<br/>AWS Secrets Manager<br/>HashiCorp Vault"]
subgraph NEVER ["NEVER DO THIS"]
N1["Hardcode in source code"]
N2["Commit .env to git"]
N3["Log secrets to console"]
N4["Send secrets in URL params"]
end
subgraph ALWAYS ["ALWAYS DO THIS"]
A1["Add .env to .gitignore FIRST"]
A2["Rotate exposed credentials"]
A3["Use read-only tokens when possible"]
A4["Audit access regularly"]
end
style DOTENV fill:#51cf66,stroke:#27ae60,color:#fff
style CI_SECRETS fill:#4a9eff,stroke:#2670c2,color:#fff
style ENV_VARS fill:#ff922b,stroke:#e8590c,color:#fff
style VAULT fill:#cc5de8,stroke:#9c36b5,color:#fff
style NEVER fill:#ff6b6b,stroke:#c92a2a,color:#fff
style ALWAYS fill:#51cf66,stroke:#27ae60,color:#fff