fix(httpapi): no-store 接线、图片缓存头时序、解压炸弹上限与 RSS 空日期
/api/admin/* 挂 NoStore、/api/me 内联 no-store(P1-3); 图片缓存头移至数据读取成功后,404 不携带 public immutable(P2-9); 上传先 DecodeConfig 限制像素 ≤2^25 再解码(P2-12); 无公开笔记时省略 lastBuildDate(P2-10)。
This commit is contained in:
@@ -274,6 +274,10 @@ func (s *Server) handleAdminTrashRestore(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
// ---- 图片上传(§7.4)----
|
||||
|
||||
// maxImagePixels 解码像素总数上限(1<<25 ≈ 8K 分辨率 7680×4320 ≈ 3.3×10⁷),
|
||||
// 防高压缩比小体积图片解码后内存放大(解压炸弹)。
|
||||
const maxImagePixels = 1 << 25
|
||||
|
||||
var allowedUploadTypes = map[string]string{
|
||||
"image/png": ".png",
|
||||
"image/jpeg": ".jpg",
|
||||
@@ -340,8 +344,19 @@ func (s *Server) handleAdminImageUpload(w http.ResponseWriter, r *http.Request)
|
||||
writeError(w, http.StatusUnsupportedMediaType, "unsupported_media", "文件内容不是受支持的图片(魔数校验失败,SVG 一律拒绝)")
|
||||
return
|
||||
}
|
||||
// 解码校验(PNG/JPEG/GIF;WebP 由魔数保证)——拦截截断/伪造的图片流
|
||||
// 解码校验(PNG/JPEG/GIF;WebP 由魔数保证)——拦截截断/伪造的图片流。
|
||||
// 先 DecodeConfig 限制像素总数:防 ≤5MB 高压缩比图片解码后撑爆内存
|
||||
// (解压炸弹 OOM,评审 round2 P2-12)。
|
||||
if magicMime != "image/webp" {
|
||||
cfg, _, err := image.DecodeConfig(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
writeError(w, http.StatusUnsupportedMediaType, "unsupported_media", "图片解码失败")
|
||||
return
|
||||
}
|
||||
if cfg.Width <= 0 || cfg.Height <= 0 || int64(cfg.Width)*int64(cfg.Height) > maxImagePixels {
|
||||
writeError(w, http.StatusRequestEntityTooLarge, "too_large", "图片像素总数超过上限")
|
||||
return
|
||||
}
|
||||
if _, _, err := image.Decode(bytes.NewReader(data)); err != nil {
|
||||
writeError(w, http.StatusUnsupportedMediaType, "unsupported_media", "图片解码失败")
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user