[测试技术] 文件上传功能怎么测:格式、大小、并发与安全

原创内容,未获授权禁止转载、转发、抄袭。

文件上传看起来只是选择文件、点击提交,背后却会经过浏览器或客户端、网关、业务服务、对象存储、病毒扫描和下载接口。任何一层处理不一致,都可能留下难复现的问题:前端提示上传成功,存储里只有半个文件;扩展名校验通过,实际内容却是脚本;同一请求重试两次,附件数量和存储对象都翻倍;用户退出项目后,仍能通过旧地址下载附件。

本文用"报销单附件"作为贯穿案例。接口允许上传 PDF、PNG 和 JPEG,单文件不超过 10 MiB,每张报销单最多 5 个附件;文件先进入隔离区,扫描通过后才能下载。下面不罗列一张庞大的测试点清单,而是从一批可复用的测试文件出发,完整走一遍上传、存储、扫描和下载链路。域名、账号、文件和接口均为演示数据,命令只应在授权的测试环境执行。

先拿到一份能判定结果的契约

本文示例接口约定如下:

http 复制代码
POST /api/claims/{claimId}/attachments HTTP/1.1
Authorization: Bearer <access-token>
Content-Type: multipart/form-data; boundary=...

file=<binary>

上传成功返回 201,文件状态先置为 SCANNING

json 复制代码
{
  "attachmentId": "att-10001",
  "originalName": "invoice.png",
  "size": 6821,
  "mediaType": "image/png",
  "sha256": "<digest>",
  "status": "SCANNING"
}

测试前需要和产品、开发确认这些规则:

  • 大小单位是 10 MiB(10 * 1024 * 1024 字节),还是 10 MB(10 * 1000 * 1000 字节);
  • 允许格式按扩展名、请求 Content-Type、文件签名还是内容解析结果判断;
  • 同名文件是允许共存、覆盖旧文件,还是返回重复错误;
  • 第 6 个附件是整次请求失败,还是上传成功后删除最早文件;
  • 扫描失败、超时和服务不可用时,文件能否下载、是否自动重试;
  • 删除附件后,对象存储何时清理,审计记录保留多久。

这些规则没有结论时,测试只能记录现象,不能自行把某种实现判为正确。本文采用"服务端生成存储名、同名可共存、第 6 个附件返回 ATTACHMENT_LIMIT_EXCEEDED、扫描通过后才能下载"的契约。

准备一组能重复使用的文件

边界文件最好由项目认可的工具生成一次,放进团队测试样本库,并在每次执行前校验字节数和解析结果。直接给普通文件补零可能破坏 PDF 或图片结构,得到的只是"扩展名正确"的无效文件。先建立独立目录并准备异常样本:

bash 复制代码
set -eu

WORK_DIR="$(mktemp -d)"
trap 'rm -rf "$WORK_DIR"' EXIT

# 零字节异常样本。
: > "$WORK_DIR/empty.pdf"

# 扩展名与内容不一致。
printf '%s\n' '<script>alert(1)</script>' > "$WORK_DIR/fake-image.jpg"
printf '%s\n' 'plain text' > "$WORK_DIR/invoice.php.jpg"

# 文件名边界。
printf '%s\n' 'test' > "$WORK_DIR/报销单 2026 (终版).txt"
printf '%s\n' 'test' > "$WORK_DIR/name-without-extension"

wc -c "$WORK_DIR"/*

从团队维护的测试样本库复制三份普通文件和三份大小边界 PDF。不要把普通文本改个扩展名当作正常样本:

bash 复制代码
cp /path/to/test-assets/invoice.png "$WORK_DIR/invoice.png"
cp /path/to/test-assets/invoice.jpg "$WORK_DIR/invoice.jpg"
cp /path/to/test-assets/invoice.pdf "$WORK_DIR/invoice.pdf"
cp /path/to/test-assets/invoice-under-limit.pdf "$WORK_DIR/invoice-under-limit.pdf"
cp /path/to/test-assets/invoice-at-limit.pdf "$WORK_DIR/invoice-at-limit.pdf"
cp /path/to/test-assets/invoice-over-limit.pdf "$WORK_DIR/invoice-over-limit.pdf"

上传前校验三个边界文件的精确字节数,并确认它们都能被项目 PDF 解析器打开:

bash 复制代码
check_pdf() {
  ACTUAL_SIZE=$(wc -c < "$1" | tr -d ' ')
  test "$ACTUAL_SIZE" = "$2"
  test "$(file --mime-type -b "$1")" = 'application/pdf'
}

check_pdf "$WORK_DIR/invoice-under-limit.pdf" 10485759
check_pdf "$WORK_DIR/invoice-at-limit.pdf" 10485760
check_pdf "$WORK_DIR/invoice-over-limit.pdf" 10485761

file 只能做基础识别,不能代替业务使用的 PDF 解析器;团队生成样本时还应跑一次项目解析流程并保存结果。普通合法文件上传前同样记录大小和摘要:

bash 复制代码
FILE="$WORK_DIR/invoice.png"
wc -c "$FILE"
shasum -a 256 "$FILE"
file --mime-type "$FILE"

测试文件目录不要混入真实身份证、发票或患者资料。需要验证隐私数据时,使用合成内容,并在测试完成后清理对象存储和本地临时文件。

正常上传要核对四层结果

先跑通一份合法 PNG。让 curl 生成 multipart boundary,不要手工写 Content-Type,否则 boundary 与请求体不一致时,测到的是构造错误:

bash 复制代码
API_URL='https://api.example.test'
CLAIM_ID='claim-upload-normal'
FILE="$WORK_DIR/invoice.png"
CURL_AUTH_CONFIG="$WORK_DIR/curl-auth.conf"

read -r -s -p '测试 Access Token: ' ACCESS_TOKEN
printf '\n'
umask 077
printf 'header = "Authorization: Bearer %s"\n' "$ACCESS_TOKEN" > "$CURL_AUTH_CONFIG"
unset ACCESS_TOKEN

HTTP_CODE=$(curl -sS --config "$CURL_AUTH_CONFIG" \
  "$API_URL/api/claims/$CLAIM_ID/attachments" \
  -F "file=@$FILE;type=image/png" \
  -o "$WORK_DIR/upload.json" \
  -w '%{http_code}')

test "$HTTP_CODE" = '201'
ATTACHMENT_ID=$(jq -er '.attachmentId' "$WORK_DIR/upload.json")
SERVER_SHA256=$(jq -er '.sha256' "$WORK_DIR/upload.json")
LOCAL_SHA256=$(shasum -a 256 "$FILE" | awk '{print $1}')
test "$SERVER_SHA256" = "$LOCAL_SHA256"
jq '{attachmentId, originalName, size, mediaType, sha256, status}' \
  "$WORK_DIR/upload.json"

认证头保存在权限受限的临时配置中,避免 Token 出现在命令行参数和 Shell 历史里;退出当前终端时会随 $WORK_DIR 一起删除。后续命令复用 CURL_AUTH_CONFIG,如果分开执行代码块,需要重新设置这些变量。

一次正常上传至少要核对四层:

层次 检查内容
HTTP 返回 201,附件 ID 唯一,文件名、大小和媒体类型符合契约
元数据 报销单、上传用户、对象 Key、摘要和 SCANNING 状态正确
对象存储 对象存在、长度一致,Key 由服务端生成且存储桶不公开
异步扫描 状态最终变为 AVAILABLE,期间下载接口拒绝访问

异步状态不能靠固定休眠猜测。先在 SCANNING 状态请求下载,本文契约要求返回 423FILE_SCANNING,且不能返回文件内容:

bash 复制代码
PRE_SCAN_HTTP=$(curl -sS --config "$CURL_AUTH_CONFIG" \
  -D "$WORK_DIR/pre-scan.headers" \
  -o "$WORK_DIR/pre-scan.json" \
  -w '%{http_code}' \
  "$API_URL/api/attachments/$ATTACHMENT_ID/content")

test "$PRE_SCAN_HTTP" = '423'
grep -qi '^content-type: application/json' "$WORK_DIR/pre-scan.headers"
jq -e '.code == "FILE_SCANNING"' "$WORK_DIR/pre-scan.json" >/dev/null

确认拦截后,再在 30 秒范围内轮询附件状态。项目应按扫描服务的实际 SLA 调整超时:

bash 复制代码
DEADLINE=$((SECONDS + 30))
while :; do
  STATUS=$(curl -sS --config "$CURL_AUTH_CONFIG" \
    "$API_URL/api/attachments/$ATTACHMENT_ID" | jq -er '.status')
  case "$STATUS" in
    AVAILABLE) break ;;
    REJECTED|FAILED) printf 'scan ended with %s\n' "$STATUS" >&2; exit 1 ;;
  esac
  test "$SECONDS" -lt "$DEADLINE" || {
    printf 'scan timeout, last status=%s\n' "$STATUS" >&2
    exit 1
  }
  sleep 1
done

状态变为 AVAILABLE 后再下载并比较摘要,能发现传输截断、错误转码和对象串用:

bash 复制代码
curl -sS --config "$CURL_AUTH_CONFIG" \
  "$API_URL/api/attachments/$ATTACHMENT_ID/content" \
  -o "$WORK_DIR/downloaded.png"

shasum -a 256 "$FILE" "$WORK_DIR/downloaded.png"
cmp "$FILE" "$WORK_DIR/downloaded.png"

如果响应带有服务端计算的 sha256,还要与本地摘要比较。只验证页面缩略图能显示,会漏掉原文件损坏、元数据关联错误和对象存储公开访问等问题。

正常链路跑通后,把 CLAIM_ID 换成另一个用户、另一个租户、已关闭和不存在的报销单,使用同一文件再次上传。服务端应在写对象前完成目标资源鉴权;失败请求不能创建附件元数据、临时对象、扫描任务或"上传失败"的空记录。只验证下载权限,会漏掉攻击者向他人业务单据写入文件的风险。

扩展名、MIME 和内容要交叉测试

浏览器文件选择框的 accept 只能帮助用户筛选,不能作为服务端安全校验。用 curl 可以绕过前端限制,分别改变文件名、multipart 的媒体类型和真实内容:

bash 复制代码
CLAIM_ID='claim-upload-format'

# 文本内容伪装成 JPEG。
curl -sS -i --config "$CURL_AUTH_CONFIG" \
  "$API_URL/api/claims/$CLAIM_ID/attachments" \
  -F "file=@$WORK_DIR/fake-image.jpg;type=image/jpeg"

# 合法 PNG 使用错误的请求媒体类型。
curl -sS -i --config "$CURL_AUTH_CONFIG" \
  "$API_URL/api/claims/$CLAIM_ID/attachments" \
  -F "file=@$WORK_DIR/invoice.png;type=text/plain"

# 双扩展名。
curl -sS -i --config "$CURL_AUTH_CONFIG" \
  "$API_URL/api/claims/$CLAIM_ID/attachments" \
  -F "file=@$WORK_DIR/invoice.php.jpg;type=image/jpeg"

本文契约要求服务端同时检查扩展名允许列表、文件签名和内容解析结果,因此三类伪装都不能进入可下载状态。失败后继续查副作用:附件数量不增加,没有可访问对象,没有触发后续 OCR 或缩略图任务,日志中也不保存完整文件内容。

页面通常只会发送一个 file 字段,直接调用接口还要补三种请求:

bash 复制代码
# 零字节文件。
curl -sS -i --config "$CURL_AUTH_CONFIG" \
  "$API_URL/api/claims/$CLAIM_ID/attachments" \
  -F "file=@$WORK_DIR/empty.pdf;type=application/pdf"

# multipart 中没有 file 字段。
curl -sS -i --config "$CURL_AUTH_CONFIG" \
  "$API_URL/api/claims/$CLAIM_ID/attachments" \
  -F 'description=missing-file'

# 同一请求重复两个 file 字段。
curl -sS -i --config "$CURL_AUTH_CONFIG" \
  "$API_URL/api/claims/$CLAIM_ID/attachments" \
  -F "file=@$WORK_DIR/invoice.png;type=image/png" \
  -F "file=@$WORK_DIR/invoice.pdf;type=application/pdf"

本文接口一次只接受一个非空文件,因此三种请求都应整体失败,不能由框架静默选择第一个或最后一个文件。若业务支持批量上传,则需要单独定义部分失败、事务边界和返回结构,不能沿用单文件接口的预期。

图片还要准备损坏文件、超大像素尺寸和正常体积但解压后占用很大的样本。PDF 则关注加密文件、损坏交叉引用表、嵌入附件、JavaScript 动作和解析超时。此类样本应来自内部安全样本库,在隔离测试环境使用;不要从未知网站下载后直接放进办公网络。

大小限制要穿过网关和应用两层

如果网关限制 8 MiB,业务接口限制 10 MiB,那么 9 MiB 文件永远到不了业务服务。网关通常限制的是包含 multipart boundary 和字段头的整个请求体,若网关与文件上限都配置为 10 MiB,恰好 10 MiB 的文件也可能被网关提前拒绝。测试前先核对各层配置,再发送前面准备的三份合法 PDF。

bash 复制代码
CLAIM_ID='claim-upload-size'

upload_size_case() {
  LABEL="$1"
  PDF_FILE="$2"
  HTTP_CODE=$(curl -sS --config "$CURL_AUTH_CONFIG" \
    -D "$WORK_DIR/size-$LABEL.headers" \
    -o "$WORK_DIR/size-$LABEL.json" \
    -w '%{http_code}' \
    "$API_URL/api/claims/$CLAIM_ID/attachments" \
    -F "file=@$PDF_FILE;type=application/pdf")
}

upload_size_case under "$WORK_DIR/invoice-under-limit.pdf"
test "$HTTP_CODE" = '201'

upload_size_case exact "$WORK_DIR/invoice-at-limit.pdf"
test "$HTTP_CODE" = '201'

upload_size_case over "$WORK_DIR/invoice-over-limit.pdf"
test "$HTTP_CODE" = '413'
grep -qi '^content-type: application/json' "$WORK_DIR/size-over.headers"
jq -e '.code == "FILE_TOO_LARGE"' "$WORK_DIR/size-over.json" >/dev/null

本文契约要求小于和等于 10 MiB 的合法文件成功,大于 1 字节的文件返回 413FILE_TOO_LARGE。响应头和响应体都被保留,因此可以区分网关 HTML 错误与业务 JSON;如果网关负责拒绝,也应按团队约定转换成同一错误结构,不能返回 HTML 502 或让客户端一直停在 99%。服务端还要在读取完整请求体之前尽早拒绝明显超限的上传,避免大文件占满内存和临时磁盘。

还要观察失败后的资源:临时目录没有残留文件,对象存储没有未关联分片,数据库没有永久停留在 UPLOADING 的记录。同一测试在直连业务服务和经过网关两条路径各跑一次,能快速定位限制来自哪一层。

文件名测试要看存储名和下载响应

文件名至少覆盖空扩展名、多个点、前后空格、中文、emoji、超长名称和路径字符。真正危险的不是页面显示难看,而是服务端把用户文件名直接拼到磁盘路径或对象 Key 中。

发送 multipart 时可以用 filename= 覆盖上传文件名:

bash 复制代码
CLAIM_ID='claim-upload-filename'

curl -sS -i --config "$CURL_AUTH_CONFIG" \
  "$API_URL/api/claims/$CLAIM_ID/attachments" \
  -F "file=@$WORK_DIR/invoice.png;filename=../../outside.png;type=image/png"

curl -sS -i --config "$CURL_AUTH_CONFIG" \
  "$API_URL/api/claims/$CLAIM_ID/attachments" \
  -F "file=@$WORK_DIR/invoice.png;filename=报销单%0d%0aX-Test:1.png;type=image/png"

第二个请求发送的是 CRLF 的百分号编码序列,用来发现服务端是否会先解码再拼接响应头;验证原始 CRLF 字节时,应使用安全测试代理构造 multipart 请求并保留原始报文。服务端可以拒绝危险名称,也可以安全规范化后保存,但对象 Key 必须由服务端生成,不能出现 ../、反斜杠或用户控制的目录。下载响应中的 Content-Disposition 也要检查,文件名需要正确编码,不能借 CRLF 注入额外响应头。

同名上传要连续执行两次。本文契约允许共存,因此应生成两个附件 ID 和两个对象 Key,下载内容分别对应各自摘要;如果项目采用覆盖策略,则必须验证权限、版本记录和并发覆盖规则,不能只看列表中"还剩一条"。

第 6 个附件要检查原子性

使用独立报销单先上传 4 个合法附件,确认基线数量后再并发提交两个新文件:

bash 复制代码
CLAIM_ID='claim-upload-limit'

for number in 1 2 3 4; do
  curl -sS --config "$CURL_AUTH_CONFIG" \
    "$API_URL/api/claims/$CLAIM_ID/attachments" \
    -F "file=@$WORK_DIR/invoice.png;filename=existing-$number.png;type=image/png" \
    -o "$WORK_DIR/existing-$number.json"
done

BASELINE_COUNT=$(curl -sS --config "$CURL_AUTH_CONFIG" \
  "$API_URL/api/claims/$CLAIM_ID/attachments" | jq -er '.items | length')
test "$BASELINE_COUNT" = '4'

for name in a b; do
  curl -sS --config "$CURL_AUTH_CONFIG" \
    "$API_URL/api/claims/$CLAIM_ID/attachments" \
    -F "file=@$WORK_DIR/invoice.png;filename=$name.png;type=image/png" \
    -o "$WORK_DIR/limit-$name.json" \
    -w '%{http_code}' > "$WORK_DIR/limit-$name.status" &
done
wait

SUCCESS_COUNT=$(grep -l '^201$' "$WORK_DIR"/limit-*.status | wc -l | tr -d ' ')
LIMIT_COUNT=$(jq -s '[.[] | select(.code == "ATTACHMENT_LIMIT_EXCEEDED")] | length' \
  "$WORK_DIR"/limit-*.json)
FINAL_COUNT=$(curl -sS --config "$CURL_AUTH_CONFIG" \
  "$API_URL/api/claims/$CLAIM_ID/attachments" | jq -er '.items | length')

test "$SUCCESS_COUNT" = '1'
test "$LIMIT_COUNT" = '1'
test "$FINAL_COUNT" = '5'

最终只能新增一个附件,总数为 5;另一个请求返回 ATTACHMENT_LIMIT_EXCEEDED。数据库不能生成两条有效记录,对象存储也不能留下失败请求的孤儿对象。连续执行一次"删除 1 个附件再上传",确认计数释放时机与对象异步清理互不干扰。

如果客户端会自动重试,再为上传请求增加幂等键。制造"服务端已经保存,但响应在网关处超时"的场景,然后用同一幂等键重试;最终只应有一个附件 ID 和一个有效对象。换一个幂等键再次上传同一文件,则按同名策略处理,不能把内容摘要误当成全局幂等键。

故障注入要覆盖跨系统部分成功

参数校验失败通常发生在写存储之前,真正容易留下脏数据的是某一步已经成功、下一步失败。测试环境可以使用受权限控制的 Failpoint、故障代理或暂停依赖服务来制造下面四个断点,不能把故障开关注入生产接口:

故障位置 注入动作 通过条件
对象写入后、元数据提交前 让数据库提交失败 接口失败,对象被补偿删除,不存在附件记录
元数据提交后、扫描事件发送前 暂停消息服务或让发布失败 记录不会永久停在 SCANNING,恢复后只补发一次有效任务
扫描完成后、状态回写前 让状态更新失败 重试后得到一个最终状态,扫描结果不会被旧状态覆盖
元数据删除后、对象删除前 让对象存储删除失败 用户不可再下载,清理任务最终删除孤儿对象

每个断点都使用新的报销单和文件摘要,记录附件 ID、对象 Key、任务 ID 和故障时间。恢复依赖后轮询到约定的最终状态,再查询对象存储和任务表;只看接口当时返回 500,无法证明补偿已经完成。对于采用 Outbox、事务消息或定时对账的系统,还要检查重复执行不会创建第二个对象、第二条扫描任务或把已拒绝文件重新发布。

中断、分片和断点续传要查未完成状态

普通 multipart 上传可以在发送过程中断网或终止客户端,观察服务端是否释放临时文件和连接。测试时不要只关闭页面,因为浏览器可能已经把请求体发送完。下面使用合法的 10 MiB PDF,将上传限速为 100 KiB/s,并在 2 秒后由客户端主动中止:

bash 复制代码
CLAIM_ID='claim-upload-interrupt'

set +e
curl -sS --config "$CURL_AUTH_CONFIG" \
  --limit-rate 100K --max-time 2 \
  "$API_URL/api/claims/$CLAIM_ID/attachments" \
  -F "file=@$WORK_DIR/invoice-at-limit.pdf;filename=interrupted.pdf;type=application/pdf" \
  -o "$WORK_DIR/interrupted.json"
CURL_RC=$?
set -e

test "$CURL_RC" = '28'
INTERRUPTED_COUNT=$(curl -sS --config "$CURL_AUTH_CONFIG" \
  "$API_URL/api/claims/$CLAIM_ID/attachments" |
  jq -er '[.items[] | select(.originalName == "interrupted.pdf")] | length')
test "$INTERRUPTED_COUNT" = '0'

退出码 28 表示这次请求确实因超时中止,列表接口也没有可见附件。随后仍要从服务端日志确认连接实际中断和已接收字节数,再检查临时文件、元数据和对象存储;其他退出码应先排查 DNS、TLS、鉴权或连接错误,不能记为中断上传通过。

如果系统使用分片上传,需要先明确 uploadId、分片编号、分片摘要、合并和取消接口。至少执行这些动作:

  • 缺少中间分片后请求合并,必须失败且不能生成可下载文件;
  • 重复上传同一分片,按契约覆盖或幂等处理,不能重复计入总大小;
  • 交换分片编号,合并后的摘要必须不匹配并失败;
  • 两个用户交换 uploadId,服务端必须拒绝;
  • 合并请求并发执行两次,只生成一个最终对象;
  • 取消或超时后继续上传旧分片,不能恢复已失效任务。

每次失败都要检查分片生命周期。未完成分片应在约定时间后清理,已合并分片不应继续占用双份空间,合并失败也不能留下一个能被下载的半成品。

扫描期间和扫描失败都不能直接下载

上传响应返回 SCANNING 后,立即请求下载接口,预期是 423409 或项目约定的不可用错误,而不是提前返回原文件。扫描通过后状态变为 AVAILABLE,扫描不通过则变为 REJECTED,并删除或隔离对象。

病毒扫描使用安全团队批准的测试样本,例如 EICAR 测试文件,不要自行制作或传播恶意程序。消息系统可能重复投递扫描任务,因此要验证处理幂等:同一附件即使被扫描多次,也只能得到一个最终状态,不能重复进入 OCR、预览和分享链路。用户应收到明确提示,安全审计记录包含附件 ID 和命中规则但不包含文件原文。

扫描服务超时时,系统应进入明确的重试或失败状态。不要把超时默认当作"扫描通过",也不要无限停留在 SCANNING。可以暂停测试扫描服务,记录重试次数、最终状态和临时对象清理时间,再恢复服务验证补偿任务是否会重复发布附件。

下载接口继续验证权限和响应头

上传成功不代表下载安全。使用以下身份请求同一个附件:上传者、同项目其他成员、无项目权限用户、另一个租户用户和未登录用户。只有契约允许的身份可以拿到内容;越权请求失败后,不能通过对象存储直链绕过业务鉴权。

下载响应至少检查:

  • Content-Type 与服务端识别结果一致,不盲信上传请求值;
  • Content-Disposition 的文件名可正确显示,且不能注入响应头;
  • 对可能被浏览器解释的内容设置合适的下载方式和 X-Content-Type-Options: nosniff
  • 私有对象的签名 URL 有短有效期,并绑定正确对象和操作;
  • 删除、驳回或权限回收后,旧下载地址按契约失效。

签名 URL 不要写入普通访问日志、埋点和缺陷截图。验证过期时应使用测试环境可配置的短有效期,避免长时间等待,也不要通过修改本机时间代替服务端过期判断。

回归时保留这些场景

场景 执行动作 关键证据
正常上传 上传合法 PNG 并下载 状态流转、对象长度、上传前后摘要一致
格式伪装 文本内容命名为 .jpg 拒绝上传,无对象、无后续任务
大小边界 上传上限值和上限加 1 字节文件 临界值结果、网关与应用错误来源
危险文件名 使用路径和 CRLF 编码序列作为文件名 对象 Key 安全,响应头未被注入
同名文件 连续上传两份同名不同内容文件 结果符合共存或覆盖契约
数量并发 已有 4 个附件时并发上传 2 个 最终总数为 5,无孤儿对象
响应丢失重试 保存成功后让响应超时,再用同一幂等键重试 只有一个附件和对象
部分成功 在存储、数据库和消息之间注入失败 补偿完成,无永久中间状态和重复任务
分片异常 缺片、乱序或并发合并 合并失败或幂等成功,无半成品下载
扫描失败 上传批准的安全测试样本 状态为 REJECTED,不进入预览和分享链路
下载越权 跨项目、跨租户和未登录下载 请求被拒绝,存储直链不可绕过

这些场景适合作为上传模块的主回归集。格式列表、大小限制、附件数量或存储链路发生变化时,再按变更点扩展测试,不需要每次机械重跑所有低风险文件名组合。

总结

文件上传测试需要把一个文件从请求体追到最终下载:请求是否被正确解析,元数据和对象是否一致,异常请求有没有留下副作用,扫描前后的状态是否可控,下载时权限和响应头是否仍然安全。扩展名、大小和页面提示只是入口,真正能定位问题的是文件摘要、对象 Key、状态流转、任务记录和下载结果组成的证据链。

先用脚本固定测试文件,再围绕正常上传、边界、并发、中断和安全场景复用同一批数据,回归会比临时找几个附件点击上传稳定得多。

相关推荐
数据知道1 小时前
网络安全实战:子域名接管实战——从 CNAME 配置错误到完全控制
网络·安全·web安全·网络安全
Aision_4 小时前
代码安全学习手记(二):SCA 软件成分分析原理与 OWASP Dependency-Check 集成实战
运维·人工智能·学习·安全·web安全·网络安全
虹科网络安全4 小时前
从33.2%降至4.2%:KnowBe4 2026报告揭示持续培训如何重塑企业安全防线
安全
是隼人5 小时前
buuctf-pwn bjdctf_2020_babystack2题解 整数溢出(学习过程持续更新)
c语言·学习·安全·pwn入门·ctf入门
艺杯羹5 小时前
古典密码学攻防演进全景:从凯撒移位、频率分析到一次一密与恩尼格玛机破译
网络·人工智能·安全·网络安全·密码学·密码安全
MartinYeung56 小时前
Aztec Connect 黑客攻击深度剖析:结算边界绕过漏洞
安全·区块链
MartinYeung56 小时前
[论文学习]Latent Fusion Jailbreak: 融合有害与无害表征以诱导大语言模型产生不安全输出
学习·安全·语言模型
飞飞传输6 小时前
机器人行业数据流转深度研究:内外网数据摆渡平台应用现状与趋势
大数据·运维·安全
tech讯息7 小时前
企业 AI Agent 对接外部服务如何安全集成?—— 多租户业务场景优先选用 WebSocket 方案
人工智能·websocket·安全