package httpapi import ( "bytes" "encoding/binary" "hash/crc32" "image" "net/http" "testing" ) // pngWithDims 构造仅含文件签名 + IHDR 的 PNG 头(DecodeConfig 只解析头部即可 // 得到宽高,无需真实像素数据;CRC 按 PNG 规范计算)。 func pngWithDims(w, h uint32) []byte { ihdr := make([]byte, 13) binary.BigEndian.PutUint32(ihdr[0:4], w) binary.BigEndian.PutUint32(ihdr[4:8], h) // 8bit / truecolor / deflate / adaptive / no interlace ihdr[8], ihdr[9], ihdr[10], ihdr[11], ihdr[12] = 8, 2, 0, 0, 0 chunk := bytes.NewBuffer(nil) _ = binary.Write(chunk, binary.BigEndian, uint32(len(ihdr))) chunk.WriteString("IHDR") chunk.Write(ihdr) _ = binary.Write(chunk, binary.BigEndian, crc32.ChecksumIEEE(chunk.Bytes()[4:])) out := bytes.NewBuffer(nil) out.Write([]byte{0x89, 'P', 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}) out.Write(chunk.Bytes()) return out.Bytes() } // TestUploadPixelBomb 解压炸弹防御(评审 round2 P2-12):小体积超大尺寸图片 // 在 DecodeConfig 阶段被 413 拒绝,不进入全量 Decode。 func TestUploadPixelBomb(t *testing.T) { // 头部自证合法:DecodeConfig 可解析出宽高 bomb := pngWithDims(20000, 20000) // 4 亿像素 > 1<<25 if _, _, err := image.DecodeConfig(bytes.NewReader(bomb)); err != nil { t.Fatalf("夹具应可解析出尺寸: %v", err) } // 正常小图不受影响 if _, _, err := image.DecodeConfig(bytes.NewReader(png1x1)); err != nil { t.Fatalf("1x1 夹具应合法: %v", err) } e := newEnv(t) c := e.loginAdmin() // 手工 multipart(uploadPNG 辅助对非 201 会 Fatal) var body bytes.Buffer boundary := "bombboundary456" body.WriteString("--" + boundary + "\r\n") body.WriteString(`Content-Disposition: form-data; name="file"; filename="bomb.png"` + "\r\n") body.WriteString("Content-Type: image/png\r\n\r\n") body.Write(bomb) body.WriteString("\r\n--" + boundary + "--\r\n") req, err := http.NewRequest(http.MethodPost, e.ts.URL+"/api/admin/images", &body) if err != nil { t.Fatal(err) } req.Header.Set("Content-Type", "multipart/form-data; boundary="+boundary) req.Header.Set("Origin", e.ts.URL) req.Header.Set("X-CSRF-Token", e.csrf) resp, err := c.Do(req) if err != nil { t.Fatal(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusRequestEntityTooLarge { t.Fatalf("超大像素图片应 413,实际 %d", resp.StatusCode) } }