安全加固:CORS白名单、JWT密钥自动生成、SSRF防护、路径遍历与错误信息泄露修复
Build Backend JAR / build (push) Has been cancelled

This commit is contained in:
2026-08-25 18:05:28 +08:00
parent c8fb93ff29
commit 338493ecaa
12 changed files with 168 additions and 31 deletions
+18 -11
View File
@@ -11,7 +11,6 @@ import zipfile
from datetime import datetime
from pathlib import Path
from urllib.parse import quote
import traceback
import requests
from requests.adapters import HTTPAdapter
@@ -33,6 +32,7 @@ from werkzeug.security import generate_password_hash
from utils.db import get_db
from utils.auth import admin_required, login_required, get_current_admin_role
from utils.ssrf import is_internal_url
from ali_oss import upload_fileobj as oss_upload_fileobj
@@ -47,6 +47,12 @@ _backend_java_session_local = threading.local()
_internal_token_lock = threading.Lock()
IMAGE_VIDEO_DATA_PERMISSION_KEY = 'admin_image_video_task_data'
SHOP_DATA_CRAWL_DATA_PERMISSION_KEY = 'admin_shop_data_crawl_task_data'
def _internal_error(exc, status=500):
"""记录内部错误日志,仅向客户端返回通用消息,避免泄露内部信息。"""
current_app.logger.error('[admin_api] internal error: %s', exc, exc_info=True)
return jsonify({'success': False, 'error': '服务器内部错误,请稍后重试'}), status
try:
VERSION_UPLOAD_MAX_BYTES = int(os.environ.get('VERSION_UPLOAD_MAX_BYTES', str(512 * 1024 * 1024)))
except ValueError:
@@ -1022,7 +1028,7 @@ def list_users():
'admins': admins,
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)})
return _internal_error(e)
@admin_api.route('/user', methods=['POST'])
@admin_required
@@ -1113,7 +1119,7 @@ def create_user():
except pymysql.IntegrityError:
return jsonify({'success': False, 'error': '用户名已存在'})
except Exception as e:
return jsonify({'success': False, 'error': str(e)})
return _internal_error(e)
@admin_api.route('/user/<int:uid>', methods=['PUT'])
@@ -1201,7 +1207,7 @@ def update_user(uid):
pass
return jsonify({'success': False, 'error': str(exc)}), 403
except Exception as e:
return jsonify({'success': False, 'error': str(e)})
return _internal_error(e)
@admin_api.route('/user/<int:uid>', methods=['DELETE'])
@@ -1239,7 +1245,7 @@ def delete_user(uid):
return jsonify({'success': False, 'error': '用户不存在'})
return jsonify({'success': True, 'msg': '删除成功'})
except Exception as e:
return jsonify({'success': False, 'error': str(e)})
return _internal_error(e)
# ---------- 生成历史 ----------
@@ -1311,7 +1317,7 @@ def history():
})
return jsonify({'success': True, 'items': items, 'total': total, 'page': page, 'page_size': page_size})
except Exception as e:
return jsonify({'success': False, 'error': str(e)})
return _internal_error(e)
# ---------- 栏目权限配置 ----------
@@ -1634,7 +1640,7 @@ def list_shop_data_crawl_tasks():
except ValueError as exc:
return jsonify({'success': False, 'error': str(exc)}), 400
except Exception as exc:
return jsonify({'success': False, 'error': str(exc)}), 500
return _internal_error(exc)
def _load_shop_data_crawl_download_rows(result_ids):
@@ -1914,6 +1920,8 @@ def download_image_video_tasks_zip():
filename = f'task-{task_id}-video-{video_index + 1}.{extension}'
remote_response = None
try:
if is_internal_url(url):
raise ValueError('拒绝下载内网/本机地址的视频')
remote_response = requests.get(url, stream=True, timeout=(10, 120))
remote_response.raise_for_status()
with output_zip.open(filename, mode='w', force_zip64=True) as target:
@@ -2017,7 +2025,7 @@ def list_image_video_tasks():
except ValueError as exc:
return jsonify({'success': False, 'error': str(exc)}), 400
except Exception as exc:
return jsonify({'success': False, 'error': str(exc)}), 500
return _internal_error(exc)
@admin_api.route('/image-video-tasks/<int:task_id>')
@@ -2573,7 +2581,7 @@ def list_versions():
]
return jsonify({'success': True, 'items': items})
except Exception as e:
return jsonify({'success': False, 'error': str(e)})
return _internal_error(e)
# ========== 数字人版本管理(代理到 Java 后端)==========
@@ -2778,8 +2786,7 @@ def upload_version():
'msg': '上传成功',
})
except Exception as e:
traceback.print_exc()
return jsonify({'success': False, 'error': str(e)})
return _internal_error(e)
finally:
if conn is not None:
try: