You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何防止通过Curl向S3预签名URL上传恶意文件?

解决S3预签名URL上传时绕过Content-Type限制的问题

核心原因

你遇到的问题根源在于:预签名URL仅验证请求头中的Content-Type是否与签名时指定的一致,但不会校验文件的实际内容。攻击者可以伪造请求头的Content-Type为你指定的Word类型,同时上传.exe文件内容,S3只会检查请求头匹配,不会验证文件真实类型。

可行解决方案

1. 强制校验文件实际内容(推荐)

通过S3事件联动后端服务,在文件上传完成后立即校验真实类型:

  • 配置S3事件通知,当有文件上传时触发Lambda函数;
  • 在Lambda中读取文件头部字节(无需全量读取),检测实际MIME类型(比如用magic库);
  • 若实际类型不在允许列表内,直接删除该文件并记录告警。

示例Lambda伪代码:

import boto3
import magic

s3 = boto3.client('s3')
ALLOWED_MIMES = ['application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document']

def lambda_handler(event, context):
    record = event['Records'][0]['s3']
    bucket = record['bucket']['name']
    key = record['object']['key']
    
    # 读取文件前1KB用于类型检测
    file_head = s3.get_object(Bucket=bucket, Key=key)['Body'].read(1024)
    actual_mime = magic.from_buffer(file_head, mime=True)
    
    if actual_mime not in ALLOWED_MIMES:
        s3.delete_object(Bucket=bucket, Key=key)
        print(f"Removed malicious file: {key}, detected type: {actual_mime}")

2. 缩小预签名URL的滥用范围

  • 缩短有效期:将URL过期时间设为5-10分钟,减少被滥用的窗口;
  • 绑定IP段:生成URL时添加SourceIp条件,仅允许指定IP/IP段的请求使用(需在签名时附带条件)。

示例带IP限制的预签名URL生成代码(boto3):

import boto3

s3 = boto3.client('s3')
presigned_url = s3.generate_presigned_url(
    'put_object',
    Params={'Bucket': 'your-bucket', 'Key': 'target-file.docx', 'ContentType': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'},
    ExpiresIn=300,
    Conditions=[{'IpAddress': {'aws:SourceIp': '192.168.1.0/24'}}]
)

3. 客户端辅助校验(仅作补充)

在前端上传页面通过JS检测文件扩展名和本地读取的MIME类型,拦截明显不符合的文件,但这只能防普通用户,攻击者可直接绕过前端调用URL,因此必须配合后端校验。

关键提醒

预签名URL的Content-Type校验仅停留在请求头层面,无法替代真实的文件内容验证。只有结合上传后的内容检测,才能有效阻止恶意文件上传。

内容的提问来源于stack exchange,提问作者Hà Lê

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 05:07:07