fix(image): reject undecodable images with 422; cap raw file size at 20MB
- decode 失败(WebP 与其他格式)不再降级返回原始字节,防止构造的畸形文件以 图片 content-type 返回任意内容(M3) - 原始分支读前查 metadata,超 20MB 返回 413,避免超大文件撑爆内存
This commit is contained in:
parent
22e883c6d9
commit
7a6e9350fe
@ -350,9 +350,10 @@ fn process_image_blocking(
|
|||||||
img
|
img
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::warn!("WebP decode failed ({}), returning raw bytes", e);
|
// decode 失败不再降级返回原始字节(可能是构造的畸形文件,配合 nosniff
|
||||||
let ct = content_type(original_format);
|
// 构成内容混淆面),直接报错让上层返回 422(M3)。
|
||||||
return Ok((data, ct));
|
tracing::warn!("WebP decode failed ({}), rejecting", e);
|
||||||
|
return Err(StatusCode::UNPROCESSABLE_ENTITY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -362,9 +363,8 @@ fn process_image_blocking(
|
|||||||
match reader.decode() {
|
match reader.decode() {
|
||||||
Ok(img) => img,
|
Ok(img) => img,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::warn!("Image decode failed ({}), returning raw bytes", e);
|
tracing::warn!("Image decode failed ({}), rejecting", e);
|
||||||
let ct = content_type(original_format);
|
return Err(StatusCode::UNPROCESSABLE_ENTITY);
|
||||||
return Ok((data, ct));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -465,11 +465,18 @@ pub async fn serve_image(
|
|||||||
|
|
||||||
// No processing params: return raw file with long-lived cache headers.
|
// No processing params: return raw file with long-lived cache headers.
|
||||||
if params.is_empty() {
|
if params.is_empty() {
|
||||||
return match tokio::fs::read(&file_path).await {
|
// 原始分支也限制大小,避免读取超大文件撑爆内存(M3)。上限 20MB
|
||||||
Ok(data) => {
|
// 覆盖正常上传图(上传侧 MAX_FILE_SIZE=5MB),拒绝异常大文件。
|
||||||
let ct = content_type(detect_format(&path));
|
const MAX_RAW_BYTES: u64 = 20 * 1024 * 1024;
|
||||||
image_response(Bytes::from(data), ct, "public, max-age=31536000, immutable", &headers)
|
return match tokio::fs::metadata(&file_path).await {
|
||||||
}
|
Ok(meta) if meta.len() > MAX_RAW_BYTES => StatusCode::PAYLOAD_TOO_LARGE.into_response(),
|
||||||
|
Ok(_) => match tokio::fs::read(&file_path).await {
|
||||||
|
Ok(data) => {
|
||||||
|
let ct = content_type(detect_format(&path));
|
||||||
|
image_response(Bytes::from(data), ct, "public, max-age=31536000, immutable", &headers)
|
||||||
|
}
|
||||||
|
Err(_) => StatusCode::NOT_FOUND.into_response(),
|
||||||
|
},
|
||||||
Err(_) => StatusCode::NOT_FOUND.into_response(),
|
Err(_) => StatusCode::NOT_FOUND.into_response(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user