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
|
inventory_export.csv
|
||||||
config.py
|
config.py
|
||||||
|
.flask_secret_key
|
||||||
|
5
app.py
5
app.py
@ -1,6 +1,7 @@
|
|||||||
# Validate configuration before starting the app
|
# Validate configuration before starting the app
|
||||||
from functions.validate_config import validate_config
|
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)
|
config_status = validate_config(item_attributes)
|
||||||
if config_status != "Ok":
|
if config_status != "Ok":
|
||||||
@ -22,7 +23,7 @@ from routes.upload import upload_bp
|
|||||||
from routes.confirm_save import confirm_save_bp
|
from routes.confirm_save import confirm_save_bp
|
||||||
|
|
||||||
app = Flask(__name__)
|
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_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
|
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
from definitions.attributes import *
|
from definitions.attributes import *
|
||||||
|
|
||||||
app_secret_key = "test_phase_secret_key"
|
|
||||||
|
|
||||||
# MySQL information
|
# MySQL information
|
||||||
class sql_conf:
|
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