mirror of
https://github.com/snailyp/gemini-balance.git
synced 2026-06-07 08:39:55 +08:00
security: enhance API key redaction with comprehensive testing and error handling
- Refactored redaction logic to use centralized helper function - Added robust error handling in AccessLogFormatter - Improved regex patterns for better OpenAI key detection - Added comprehensive unit tests covering edge cases and error scenarios - Enhanced input validation with descriptive error placeholders
This commit is contained in:
@@ -9,7 +9,7 @@ from app.config.config import settings, sync_initial_settings
|
||||
from app.database.connection import connect_to_db, disconnect_from_db
|
||||
from app.database.initialization import initialize_database
|
||||
from app.exception.exceptions import setup_exception_handlers
|
||||
from app.log.logger import get_application_logger
|
||||
from app.log.logger import get_application_logger, setup_access_logging
|
||||
from app.middleware.middleware import setup_middlewares
|
||||
from app.router.routes import setup_routers
|
||||
from app.scheduler.scheduled_tasks import start_scheduler, stop_scheduler
|
||||
@@ -150,4 +150,7 @@ def create_app() -> FastAPI:
|
||||
# 配置路由
|
||||
setup_routers(app)
|
||||
|
||||
# 配置访问日志API密钥隐藏
|
||||
setup_access_logging()
|
||||
|
||||
return app
|
||||
|
||||
@@ -14,15 +14,7 @@ COLORS = {
|
||||
}
|
||||
|
||||
|
||||
def _redact_key_for_logging(key: str) -> str:
|
||||
"""
|
||||
Redacts API key for secure logging by showing only first and last 6 characters.
|
||||
(Internal function to avoid circular imports)
|
||||
"""
|
||||
if not key or len(key) <= 12:
|
||||
return "***"
|
||||
|
||||
return f"{key[:6]}...{key[-6:]}"
|
||||
from app.utils.helpers import redact_key_for_logging as _redact_key_for_logging
|
||||
|
||||
# Windows系统启用ANSI支持
|
||||
if platform.system() == "Windows":
|
||||
@@ -54,9 +46,8 @@ class AccessLogFormatter(logging.Formatter):
|
||||
|
||||
# API key patterns to match in URLs
|
||||
API_KEY_PATTERNS = [
|
||||
r'AIza[0-9A-Za-z_-]{35}', # Google API keys (like Gemini)
|
||||
r'sk-[0-9A-Za-z]{48}', # OpenAI API keys
|
||||
r'sk-[0-9A-Za-z_-]{20,}', # General sk- prefixed keys
|
||||
r'\bAIza[0-9A-Za-z_-]{35}', # Google API keys (like Gemini)
|
||||
r'\bsk-[0-9A-Za-z_-]{20,}', # OpenAI and general sk- prefixed keys
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -75,14 +66,21 @@ class AccessLogFormatter(logging.Formatter):
|
||||
"""
|
||||
Replace API keys in log message with redacted versions
|
||||
"""
|
||||
for pattern in self.compiled_patterns:
|
||||
def replace_key(match):
|
||||
key = match.group(0)
|
||||
return _redact_key_for_logging(key)
|
||||
try:
|
||||
for pattern in self.compiled_patterns:
|
||||
def replace_key(match):
|
||||
key = match.group(0)
|
||||
return _redact_key_for_logging(key)
|
||||
|
||||
message = pattern.sub(replace_key, message)
|
||||
message = pattern.sub(replace_key, message)
|
||||
|
||||
return message
|
||||
return message
|
||||
except Exception as e:
|
||||
# Log the error but don't expose the original message in case it contains keys
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.error(f"Error redacting API keys in access log: {e}")
|
||||
return "[LOG_REDACTION_ERROR]"
|
||||
|
||||
|
||||
# 日志格式 - 使用 fileloc 并设置固定宽度 (例如 30)
|
||||
|
||||
@@ -5,10 +5,7 @@ from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
from app.core.application import create_app
|
||||
from app.log.logger import get_main_logger, setup_access_logging
|
||||
|
||||
# Setup access logging with API key redaction when app is imported (for CLI usage)
|
||||
setup_access_logging()
|
||||
from app.log.logger import get_main_logger
|
||||
|
||||
app = create_app()
|
||||
|
||||
|
||||
@@ -162,12 +162,15 @@ def redact_key_for_logging(key: str) -> str:
|
||||
key: API key to redact
|
||||
|
||||
Returns:
|
||||
str: Redacted key in format "first6...last6" or original if too short
|
||||
str: Redacted key in format "first6...last6" or descriptive placeholder for edge cases
|
||||
"""
|
||||
if not key or len(key) <= 12:
|
||||
return "***"
|
||||
if not key:
|
||||
return key
|
||||
|
||||
return f"{key[:6]}...{key[-6:]}"
|
||||
if len(key) <= 12:
|
||||
return f"{key[:3]}...{key[-3:]}"
|
||||
else:
|
||||
return f"{key[:6]}...{key[-6:]}"
|
||||
|
||||
|
||||
def get_current_version(default_version: str = "0.0.0") -> str:
|
||||
|
||||
Reference in New Issue
Block a user