安全修复:加固CSRF与凭证保护并修复越权风险

This commit is contained in:
2026-02-16 01:19:43 +08:00
parent 14b506e8a1
commit 1389ec7434
22 changed files with 375 additions and 83 deletions

View File

@@ -14,6 +14,7 @@
import os
import sys
import base64
import threading
from pathlib import Path
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
@@ -27,18 +28,37 @@ ENCRYPTION_KEY_FILE = os.environ.get('ENCRYPTION_KEY_FILE', 'data/encryption_key
ENCRYPTION_SALT_FILE = os.environ.get('ENCRYPTION_SALT_FILE', 'data/encryption_salt.bin')
def _ensure_private_dir(path: Path) -> None:
if not path:
return
os.makedirs(path, mode=0o700, exist_ok=True)
try:
os.chmod(path, 0o700)
except Exception:
pass
def _ensure_private_file(path: Path) -> None:
try:
os.chmod(path, 0o600)
except Exception:
pass
def _get_or_create_salt():
"""获取或创建盐值"""
salt_path = Path(ENCRYPTION_SALT_FILE)
if salt_path.exists():
_ensure_private_file(salt_path)
with open(salt_path, 'rb') as f:
return f.read()
# 生成新的盐值
salt = os.urandom(16)
os.makedirs(salt_path.parent, exist_ok=True)
_ensure_private_dir(salt_path.parent)
with open(salt_path, 'wb') as f:
f.write(salt)
_ensure_private_file(salt_path)
return salt
@@ -102,6 +122,7 @@ def get_encryption_key():
key_path = Path(ENCRYPTION_KEY_FILE)
if key_path.exists():
logger.info(f"从文件 {ENCRYPTION_KEY_FILE} 读取加密密钥")
_ensure_private_file(key_path)
with open(key_path, 'rb') as f:
return f.read()
@@ -127,9 +148,10 @@ def get_encryption_key():
# 生成新的密钥
key = Fernet.generate_key()
os.makedirs(key_path.parent, exist_ok=True)
_ensure_private_dir(key_path.parent)
with open(key_path, 'wb') as f:
f.write(key)
_ensure_private_file(key_path)
logger.info(f"已生成新的加密密钥并保存到 {ENCRYPTION_KEY_FILE}")
logger.warning("请立即备份此密钥文件,并建议设置 ENCRYPTION_KEY_RAW 环境变量!")
return key
@@ -137,14 +159,17 @@ def get_encryption_key():
# 全局Fernet实例
_fernet = None
_fernet_lock = threading.Lock()
def _get_fernet():
"""获取Fernet加密器懒加载"""
global _fernet
if _fernet is None:
key = get_encryption_key()
_fernet = Fernet(key)
with _fernet_lock:
if _fernet is None:
key = get_encryption_key()
_fernet = Fernet(key)
return _fernet
@@ -187,8 +212,8 @@ def decrypt_password(encrypted_password: str) -> str:
# 解密失败,可能是旧的明文密码或密钥不匹配
if is_encrypted(encrypted_password):
logger.error(f"密码解密失败(密钥可能不匹配): {e}")
else:
logger.warning(f"密码解密失败,可能是未加密的旧数据: {e}")
return ''
logger.warning(f"密码解密失败,可能是未加密的旧数据: {e}")
return encrypted_password