## Проверять тип загружаемого файла по сигнатуре, а не по заголовку **Контекст:** `UploadHandler.UploadFile` валидировал только `header.Header.Get("Content-Type")` из multipart-части. Этот заголовок полностью контролируется клиентом, поэтому под видом `image/jpeg` можно было залить произвольный файл (HTML/JS/SVG/исполняемый контент) в общий бакет. **Суть:** Заявленный content-type — это утверждение клиента, а не факт. Доверять можно только реальным байтам файла. Проверяем сигнатуру по первым 512 байтам и затем возвращаем курсор в начало (`Seek(0,0)`), иначе загрузка прочитает усечённый файл. ```go func verifyImageSignature(file io.ReadSeeker, declaredType string) error { head := make([]byte, 512) n, _ := io.ReadFull(file, head) head = head[:n] file.Seek(0, io.SeekStart) // вернуть курсор для PutObject if !matchesImageType(head, declaredType) { return errors.New("file signature mismatch") } return nil } ``` **Нюанс:** `http.DetectContentType` распознаёт jpeg/png/webp, но **не heic**. Для HEIC проверяем ISO-BMFF бокс вручную: байты `4:8 == "ftyp"` и бренд из набора `heic/heix/hevc/mif1/...`. **Правило:** любой пользовательский upload → whitelist типов + проверка magic-bytes + генерация имени на сервере (uuid+ext), никогда не доверять имени/типу от клиента. **Связанные заметки:** [[MOC-security-patterns]], [[backend-validation]] **Источник:** Code review 2026-06-30 (neyrogovnarik), security-fix в `handlers/upload.go` #golang #backend #security #file-upload #best-practice