Django图片上传失败:SuspiciousFileOperation路径遍历错误求助
Django图片上传触发SuspiciousFileOperation错误,提示路径遍历
报错信息
django.core.exceptions.SuspiciousFileOperation: Detected path traversal attempt in '/media/uploads/87176296b7b2425e81e266eaed65019b.png' Bad Request: /api/upload_file/ Bad Request: /api/upload_file/ [03/Aug/2023 17:47:52] "POST /api/upload_file/ HTTP/1.1" 400 17430
相关代码
/api/upload_file/接口代码
def upload_file(request): request_file = request.FILES['file'] if 'file' in request.FILES else None if request_file is None: data={ "error": "No file", } return Response(status=status.HTTP_400_BAD_REQUEST, data=data) if request_file.size > 20*1024*1024: data={ "error": "Image file too large (>20mb)", } return Response(status=status.HTTP_400_BAD_REQUEST, data=data) allowed_file_types = ['jpeg', 'jpg', 'png'] file_type = imghdr.what(request_file) if file_type not in allowed_file_types: data = { "error": "Invalid file type", } return Response(status=status.HTTP_400_BAD_REQUEST, data=data) upload = Upload(image=request_file) upload.save() data = { "upload_id": upload.id, } return Response(status=status.HTTP_200_OK, data=data)
Upload模型代码
class Upload(models.Model): image = models.ImageField( verbose_name="Image", upload_to=path_and_rename_upload, ) patient = models.ForeignKey( "users.Patient", verbose_name="Patient", related_name="uploads", on_delete=models.SET_NULL, null=True, blank=True, ) upload_date = models.DateTimeField( verbose_name="Upload Date", auto_now_add=True, ) def __str__(self): return self.image.name @deconstructible class PathAndRename(object): def __init__(self, sub_path): self.path = sub_path def __call__(self, instance, filename) -> str: ext = filename.split(".")[-1] filename = f"{uuid4().hex}.{ext}".lower() return os.path.join(self.path, filename) path_and_rename_upload = PathAndRename("/media/uploads")
settings.py配置
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static') ] if not DEBUG: STATIC_ROOT = os.path.join(BASE_DIR, 'static') MEDIA_URL = '/media/' if not DEBUG: MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
问题原因及解决办法
核心问题
Django的ImageField的upload_to参数要求传入相对路径,你当前传入的"/media/uploads"是绝对路径格式,被Django判定为路径遍历攻击,触发SuspiciousFileOperation错误。修复步骤
修正
upload_to的路径参数:去掉路径开头的斜杠,改为相对路径# 原代码 path_and_rename_upload = PathAndRename("/media/uploads") # 修改后 path_and_rename_upload = PathAndRename("uploads")这样Django会自动将路径拼接在
MEDIA_ROOT之后,最终保存路径为BASE_DIR/media/uploads/xxx.png。完善MEDIA_ROOT配置:确保DEBUG模式下也有正确的MEDIA_ROOT设置(当前仅在非DEBUG时配置,会导致DEBUG模式下路径异常)
MEDIA_URL = '/media/' # 统一设置,覆盖原条件判断 MEDIA_ROOT = os.path.join(BASE_DIR, 'media')保留路径生成逻辑:你的
PathAndRename类的路径拼接逻辑无需修改,只要传入的sub_path是相对路径,os.path.join会自动生成符合要求的相对路径。
- 验证结果
修复后,上传的文件会被保存到BASE_DIR/media/uploads/目录,数据库中存储的路径为uploads/xxx.png,通过MEDIA_URL可以正常访问该文件。
内容的提问来源于stack exchange,提问作者Battos
相关产品推荐
相关产品推荐

