diff --git a/apps/api/app/middleware/logging.py b/apps/api/app/middleware/logging.py index deded104f..c84a59325 100644 --- a/apps/api/app/middleware/logging.py +++ b/apps/api/app/middleware/logging.py @@ -3,13 +3,60 @@ """ import logging +import re import time +from typing import Optional from fastapi import Request from starlette.middleware.base import BaseHTTPMiddleware logger = logging.getLogger(__name__) +# 敏感参数名称模式(不区分大小写) +SENSITIVE_PARAM_PATTERNS = re.compile( + r'^(password|passwd|pwd|token|secret|key|authorization|auth|api_key|apikey|' + r'access_token|refresh_token|accesstoken|refreshtoken|' + r'session_id|sessionid|sid|cookie|csrf|xsrf|bearer)$', + re.IGNORECASE +) + + +def filter_sensitive_params(query_string: Optional[str]) -> Optional[str]: + """ + 过滤 query string 中的敏感参数 + + Args: + query_string: 原始 query string,例如 "name=xxx&password=secret&token=abc" + + Returns: + 过滤后的 query string,敏感参数的值被替换为 "***" + 如果 query_string 为空或 None,返回原始值 + """ + if not query_string: + return query_string + + if query_string.startswith('?'): + query_string = query_string[1:] + + if not query_string: + return query_string + + parts = query_string.split('&') + filtered_parts = [] + + for part in parts: + if '=' in part: + key, value = part.split('=', 1) + if SENSITIVE_PARAM_PATTERNS.match(key): + filtered_parts.append(f"{key}=***") + else: + filtered_parts.append(part) + else: + # 没有 = 的参数,保留原样 + filtered_parts.append(part) + + return '&'.join(filtered_parts) + class RequestLoggingMiddleware(BaseHTTPMiddleware): """请求日志中间件""" @@ -18,8 +65,15 @@ class RequestLoggingMiddleware(BaseHTTPMiddleware): # 记录请求开始时间 start_time = time.time() - # 记录请求信息 - logger.info(f"Request: {request.method} {request.url.path}") + # 过滤 query string 中的敏感参数 + raw_query = str(request.url.query) if request.url.query else "" + safe_query = filter_sensitive_params(raw_query) + + # 记录请求信息(不包含敏感参数) + if safe_query: + logger.info(f"Request: {request.method} {request.url.path}?{safe_query}") + else: + logger.info(f"Request: {request.method} {request.url.path}") # 处理请求 response = await call_next(request)