Mitigation Strategy: Disable Debug Mode in Production
-
Description:
-
Locate Configuration: Identify all places where Flask's debug mode might be enabled. This includes:
- Direct calls to
app.run(debug=True)
in your main application file (e.g.,app.py
,run.py
). - Environment variables:
FLASK_DEBUG=1
orFLASK_ENV=development
. - Configuration files (e.g.,
config.py
,.env
files).
- Direct calls to
-
Set to False: Explicitly set debug mode to
False
in production:- Remove or comment out
app.run(debug=True)
. - Set environment variables:
FLASK_DEBUG=0
andFLASK_ENV=production
. - Update configuration files to reflect
debug = False
.
- Remove or comment out
-
Use Production WSGI Server: Instead of Flask's built-in server, use a production-ready WSGI server like Gunicorn or uWSGI. Configure the WSGI server to run your Flask application. Example (Gunicorn):
gunicorn --workers 3 --bind 0.0.0.0:8000 myapp:app
-
Environment Check: Add a check in your application's startup code:
import os if os.environ.get('FLASK_ENV') == 'development': raise RuntimeError('Cannot run in development mode in production!')
-
Deployment Scripts: Ensure your deployment scripts (e.g., Dockerfile, shell scripts, CI/CD pipelines) enforce the production settings.
-
-
List of Threats Mitigated:
- Information Disclosure (High Severity): Prevents exposure of stack traces, environment variables, and source code snippets to attackers. This is directly related to Flask's debug mode features.
- Code Execution (Critical Severity): Some debuggers (though not Flask's default) allow interactive code execution. Disabling debug mode prevents this.
- Denial of Service (DoS) (Medium Severity): Debug mode can be more resource-intensive.
-
Impact:
- Information Disclosure: Risk reduced to near zero.
- Code Execution: Risk reduced to near zero.
- DoS: Risk slightly reduced.
-
Currently Implemented:
app.run(debug=True)
is removed.- Environment variables are set correctly in the production Docker container.
- Gunicorn is used as the WSGI server.
-
Missing Implementation:
- The environment check code snippet is not currently implemented in
app.py
.
- The environment check code snippet is not currently implemented in
Mitigation Strategy: Secure send_file
and send_from_directory
Usage
-
Description:
-
Identify Usage: Locate all instances of Flask's
send_file
andsend_from_directory
functions. -
Prefer
send_from_directory
: Usesend_from_directory
instead ofsend_file
when serving files from a directory. This function is provided by Flask and offers better built-in protection. -
Sanitize Filenames: Implement a sanitization function to remove dangerous characters:
import os import re def sanitize_filename(filename): filename = os.path.basename(filename) # Remove path components filename = re.sub(r"[^a-zA-Z0-9_.-]", "", filename) # Whitelist return filename
-
Validate Input: Validate the filename against a whitelist before passing it to
send_from_directory
. -
Absolute Paths: Use absolute paths for the file directory, configured via Flask's
app.config
. -
Avoid User Input in Paths: If possible, generate filenames server-side and store a mapping to the original filename.
-
-
List of Threats Mitigated:
- Directory Traversal (High Severity): Prevents accessing files outside the intended directory, a vulnerability specifically exploitable through Flask's file-serving functions.
- Information Disclosure (Medium Severity): Limits access to authorized files.
-
Impact:
- Directory Traversal: Risk significantly reduced.
- Information Disclosure: Risk significantly reduced.
-
Currently Implemented:
send_from_directory
is used in the/uploads/<filename>
route.- Absolute paths are used.
-
Missing Implementation:
- The
sanitize_filename
function is not implemented. - No whitelist validation.
- The
Mitigation Strategy: Strong and Secure SECRET_KEY
-
Description:
-
Generate a Strong Key: Use a cryptographically secure random number generator (e.g.,
secrets.token_urlsafe(64)
in Python). -
Store in Environment Variable: Never hardcode. Use an environment variable (e.g.,
SECRET_KEY
). -
Configure Flask: Load the key from the environment variable in your Flask app:
import os app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
-
Key Rotation (Ideal): Implement a process for periodic rotation.
-
Session Cookie Attributes: Set secure attributes in your Flask configuration:
app.config['SESSION_COOKIE_SECURE'] = True app.config['SESSION_COOKIE_HTTPONLY'] = True app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'
-
-
List of Threats Mitigated:
- Session Hijacking (Critical Severity): Prevents forging session cookies, a threat directly related to Flask's session management.
- Cross-Site Request Forgery (CSRF) (High Severity):
SESSION_COOKIE_SAMESITE
helps. - Cross-Site Scripting (XSS) (High Severity):
SESSION_COOKIE_HTTPONLY
helps.
-
Impact:
- Session Hijacking: Risk significantly reduced.
- CSRF: Risk reduced.
- XSS: Risk reduced.
-
Currently Implemented:
SECRET_KEY
is loaded from an environment variable.SESSION_COOKIE_SECURE
,SESSION_COOKIE_HTTPONLY
, andSESSION_COOKIE_SAMESITE
are set.
-
Missing Implementation:
- Key rotation is not implemented.
Mitigation Strategy: Custom Error Handlers
-
Description:
-
Identify Common Errors: Determine likely HTTP error codes (400, 401, 403, 404, 500, 503).
-
Create Custom Handlers: Use Flask's
@app.errorhandler()
decorator:from flask import render_template, request @app.errorhandler(404) def page_not_found(error): app.logger.warning(f"404: {request.path}") return render_template('404.html'), 404 @app.errorhandler(500) def internal_server_error(error): app.logger.error(f"500: {error}") return render_template('500.html'), 500
-
Generic Error Pages: Create generic HTML templates (e.g.,
404.html
,500.html
). -
Logging: Log detailed error information using Flask's logger (
app.logger
). -
Centralized Logging: Send logs to a centralized service.
-
-
List of Threats Mitigated:
- Information Disclosure (Medium Severity): Prevents leaking internal details through Flask's default error messages.
-
Impact:
- Information Disclosure: Risk significantly reduced.
-
Currently Implemented:
- Custom handlers for 404 and 500.
- Generic error pages exist.
- Basic console logging.
-
Missing Implementation:
- Centralized logging is not implemented.
- Missing handlers for other error codes.
Mitigation Strategy: Safe Template Rendering (Jinja2)
-
Description:
-
Autoescaping (Verify): Ensure Jinja2's autoescaping is enabled (default in Flask). Do not disable.
-
Context Variables: Always pass user data to templates as context variables. Never concatenate. Example (correct):
from flask import render_template, request @app.route('/hello') def hello(): username = request.args.get('username') return render_template('hello.html', username=username)
-
|safe
Filter (Extreme Caution): If rendering HTML from user input, sanitize thoroughly first, then use|safe
. Generally discouraged. -
Input Validation: Validate and sanitize data before passing it to the template.
-
-
List of Threats Mitigated:
- Template Injection (Critical Severity): Prevents injecting malicious code into Jinja2 templates, a vulnerability specific to the templating engine used by Flask.
- Cross-Site Scripting (XSS) (High Severity): Autoescaping prevents most XSS.
-
Impact:
- Template Injection: Risk significantly reduced.
- XSS: Risk significantly reduced.
-
Currently Implemented:
- Autoescaping is enabled.
- User data is passed as context variables.
-
Missing Implementation:
- No specific input validation before passing data to templates.