diff --git a/jyls_django/middleware.py b/jyls_django/middleware.py index 6111a4d..d3d7e4a 100644 --- a/jyls_django/middleware.py +++ b/jyls_django/middleware.py @@ -3,6 +3,7 @@ from django.utils.deprecation import MiddlewareMixin from django.urls import resolve, Resolver404 import logging from datetime import datetime +import re from rest_framework import status from User.models import User @@ -10,12 +11,76 @@ from User.models import User logger = logging.getLogger('django.server') cnt = 0 + +# 恶意扫描路径模式(常见的安全扫描路径) +MALICIOUS_PATTERNS = [ + r'^/\.env', # 环境变量文件 + r'^/\.git', # Git 仓库 + r'^/\.svn', # SVN 仓库 + r'^/\.htaccess', # Apache 配置文件 + r'^/\.htpasswd', # Apache 密码文件 + r'^/wp-admin', # WordPress 后台 + r'^/wp-login', # WordPress 登录 + r'^/phpmyadmin', # phpMyAdmin + r'^/adminer', # Adminer + r'^/\.well-known', # 证书验证目录 + r'^/\.DS_Store', # macOS 系统文件 + r'^/config\.php', # PHP 配置文件 + r'^/web\.config', # IIS 配置文件 + r'^/\.idea', # IDE 配置 + r'^/\.vscode', # VS Code 配置 + r'^/\.ssh', # SSH 密钥 + r'^/\.bash_history', # Bash 历史 + r'^/\.bashrc', # Bash 配置 + r'^/\.profile', # 用户配置 + r'^/\.zshrc', # Zsh 配置 + r'^/\.vimrc', # Vim 配置 + r'^/\.gitignore', # Git 忽略文件 + r'^/\.dockerignore', # Docker 忽略文件 + r'^/\.npmrc', # NPM 配置 + r'^/\.yarnrc', # Yarn 配置 + r'^/\.pypirc', # Python 配置 + r'^/\.pip', # pip 配置 + r'^/\.condarc', # Conda 配置 + r'^/\.m2', # Maven 配置 + r'^/\.sbt', # SBT 配置 + r'^/\.cargo', # Rust 配置 + r'^/\.nvm', # Node 版本管理 + r'^/\.rvm', # Ruby 版本管理 + r'^/\.rbenv', # Ruby 环境 + r'^/\.pyenv', # Python 环境 + r'^/\.virtualenv', # Python 虚拟环境 + r'^/\.venv', # Python 虚拟环境 + r'^/\.env\.', # 各种环境变量文件变体 +] + +# 编译恶意路径正则表达式 +MALICIOUS_PATTERNS_COMPILED = [re.compile(pattern, re.IGNORECASE) for pattern in MALICIOUS_PATTERNS] + +def is_malicious_request(path): + """检测是否为恶意请求""" + for pattern in MALICIOUS_PATTERNS_COMPILED: + if pattern.search(path): + return True + return False + class JWTAuthenticationMiddleware(MiddlewareMixin): def process_request(self, request): # OPTIONS 请求直接放行(CORS 预检请求) if request.method == 'OPTIONS': return None + # 检测恶意请求 + if is_malicious_request(request.path): + # 标记为恶意请求,用于日志过滤 + request.META['_is_malicious'] = True + return JsonResponse( + {'status': 403, 'message': "禁止访问"}, + status=403, + content_type='application/json', + headers={'Access-Control-Allow-Origin': '*'} + ) + # 处理 Authorization 头 token = request.META.get('HTTP_AUTHORIZATION') # 如果 Authorization 头格式是 "Bearer token",提取 token @@ -29,6 +94,8 @@ class JWTAuthenticationMiddleware(MiddlewareMixin): try: if not token: + # 标记为未授权请求(可能是正常的前端访问,也可能是恶意扫描) + request.META['_is_unauthorized'] = True return JsonResponse( {'status': 401,'message':"token为空"}, status=401, @@ -37,6 +104,8 @@ class JWTAuthenticationMiddleware(MiddlewareMixin): ) User.objects.get(token=token) except User.DoesNotExist: + # 标记为未授权请求 + request.META['_is_unauthorized'] = True return JsonResponse( {'status': 401,'message':"身份过期"}, status=401, @@ -191,6 +260,24 @@ class ApiLoggingMiddleware(MiddlewareMixin): response['Access-Control-Allow-Headers'] = 'Content-Type, Authorization, X-Requested-With' response['Access-Control-Allow-Credentials'] = 'true' + # 检查是否为恶意请求 + is_malicious = request.META.get('_is_malicious', False) + is_unauthorized = request.META.get('_is_unauthorized', False) + + # 如果是恶意请求,只记录简要信息,不记录详细日志 + if is_malicious: + timestamp = datetime.now().strftime('[%d/%b/%Y %H:%M:%S]') + # 只记录简要信息,避免日志噪音 + print(f'{timestamp} [恶意扫描] "{request.method} {request.path}" {response.status_code} - 已阻止') + return response + + # 如果是未授权请求且路径可疑,可能是恶意扫描 + if is_unauthorized and (request.path == '/' or is_malicious_request(request.path)): + timestamp = datetime.now().strftime('[%d/%b/%Y %H:%M:%S]') + print(f'{timestamp} [未授权访问] "{request.method} {request.path}" {response.status_code}') + return response + + # 正常请求,记录详细日志 try: # 解析URL获取view函数 resolver_match = resolve(request.path) @@ -241,9 +328,14 @@ class ApiLoggingMiddleware(MiddlewareMixin): print(log_message) except Resolver404: - # URL无法解析,使用默认日志格式 - timestamp = datetime.now().strftime('[%d/%b/%Y %H:%M:%S]') - print(f'{timestamp} "{request.method} {request.path} HTTP/1.1" {response.status_code} 未知接口') + # URL无法解析 + # 如果是未授权请求,可能是恶意扫描,只记录简要信息 + if is_unauthorized: + timestamp = datetime.now().strftime('[%d/%b/%Y %H:%M:%S]') + print(f'{timestamp} [未授权访问] "{request.method} {request.path}" {response.status_code}') + else: + timestamp = datetime.now().strftime('[%d/%b/%Y %H:%M:%S]') + print(f'{timestamp} "{request.method} {request.path} HTTP/1.1" {response.status_code} 未知接口') except Exception: # 发生异常时不影响请求处理,使用默认格式 timestamp = datetime.now().strftime('[%d/%b/%Y %H:%M:%S]')