Fix: Secret Key
Use a random-generated secret key stored in either the environment variables or in a file in the app directory instead of hard-coding.
This commit is contained in:
parent
deeaf9e645
commit
55dd86c27c
1
.gitignore
vendored
1
.gitignore
vendored
@ -162,3 +162,4 @@ cython_debug/
|
||||
|
||||
inventory_export.csv
|
||||
config.py
|
||||
.flask_secret_key
|
||||
|
5
app.py
5
app.py
@ -1,6 +1,7 @@
|
||||
# Validate configuration before starting the app
|
||||
from functions.validate_config import validate_config
|
||||
from config import item_attributes, sql_conf, app_secret_key
|
||||
from functions.secret_key import get_secret_key
|
||||
from config import item_attributes, sql_conf
|
||||
|
||||
config_status = validate_config(item_attributes)
|
||||
if config_status != "Ok":
|
||||
@ -22,7 +23,7 @@ from routes.upload import upload_bp
|
||||
from routes.confirm_save import confirm_save_bp
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = app_secret_key # Required for flashing messages and session
|
||||
app.secret_key = get_secret_key() # Required for flashing messages and session
|
||||
app.config['SQLALCHEMY_DATABASE_URI'] = f'mysql://{sql_conf.SQL_USER}:{sql_conf.SQL_PASSWORD}@{sql_conf.SQL_HOST}/{sql_conf.SQL_DB}'
|
||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||
db.init_app(app)
|
||||
|
@ -1,6 +1,5 @@
|
||||
from definitions.attributes import *
|
||||
|
||||
app_secret_key = "test_phase_secret_key"
|
||||
|
||||
# MySQL information
|
||||
class sql_conf:
|
||||
|
55
functions/secret_key.py
Normal file
55
functions/secret_key.py
Normal file
@ -0,0 +1,55 @@
|
||||
import os
|
||||
import sys
|
||||
from typing import Optional
|
||||
import secrets
|
||||
from warnings import warn
|
||||
|
||||
def get_secret_key() -> str:
|
||||
"""
|
||||
Secure secret key loader with fail-safes for different environments.
|
||||
Priority:
|
||||
1. Explicit environment variable (FLASK_SECRET_KEY)
|
||||
2. Secret file (./.flask_secret_key)
|
||||
3. Generated temporary key (development only)
|
||||
|
||||
Returns:
|
||||
str: The secret key
|
||||
|
||||
Raises:
|
||||
RuntimeError: In production if no key is configured
|
||||
"""
|
||||
# 1. Check environment variable first
|
||||
if 'FLASK_SECRET_KEY' in os.environ:
|
||||
if len(os.environ['FLASK_SECRET_KEY']) < 32:
|
||||
warn('Weak secret key (min 32 chars recommended)')
|
||||
return os.environ['FLASK_SECRET_KEY']
|
||||
|
||||
# 2. Check for secret file (Docker/K8s compatible)
|
||||
secret_file = '.flask_secret_key'
|
||||
if os.path.exists(secret_file):
|
||||
with open(secret_file) as f:
|
||||
key = f.read().strip()
|
||||
if len(key) >= 32:
|
||||
return key
|
||||
warn(f'Weak key in {secret_file} (min 32 chars)')
|
||||
|
||||
# 3. Development fallback
|
||||
if os.getenv('FLASK_ENV') == 'development':
|
||||
key = secrets.token_hex(32)
|
||||
warn(f'Using temporary development key: {key[:8]}...')
|
||||
return key
|
||||
|
||||
# 4. Production failure
|
||||
raise RuntimeError(
|
||||
"No valid secret key configured.\n"
|
||||
"Set FLASK_SECRET_KEY environment variable or "
|
||||
f"create {secret_file} with 32+ random characters."
|
||||
)
|
||||
|
||||
def generate_key() -> str:
|
||||
"""Generate a strong secret key for configuration"""
|
||||
return secrets.token_urlsafe(64) # URL-safe for easier handling
|
||||
|
||||
if __name__ == '__main__':
|
||||
# CLI for key generation
|
||||
print(f"New secret key: {generate_key()}")
|
Loading…
Reference in New Issue
Block a user