콘텐츠로 건너뛰기

파일 시그니처(매직 바이트) 목록

파일의 앞부분 몇 바이트에 들어 있는 시그니처(매직 바이트) 목록입니다. 파일 타입 판정과 검증 구현에 참고하세요.

매직 바이트란

많은 파일 형식은 파일 앞부분에 고정된 바이트 열(시그니처)을 가집니다. 이를 매직 바이트 또는 파일 시그니처라고 부릅니다. OS와 애플리케이션은 이 시그니처를 보고 파일 종류를 판정합니다. 확장자는 쉽게 위장할 수 있지만 매직 바이트는 바이너리 수준의 식별자이므로 파일 검증의 신뢰성이 높아집니다.

Linux의 file 명령이나 PHP의 finfo 클래스는 이 구조를 이용해 MIME 타입을 판정합니다.

주요 형식의 매직 바이트 (선두 N바이트) PNG JPEG GIF PDF ZIP WebP MP4 89 50 4E 47 .PNG FF D8 FF SOI marker 47 49 46 38 "GIF8" 25 50 44 46 "%PDF" 50 4B 03 04 "PK\x03\x04" 52 49 46 46 "RIFF" + WEBP at offset 8 66 74 79 70 "ftyp" at offset 4
그림: 주요 형식의 선두 바이트 (매직 바이트)

이미지 파일

형식확장자매직 바이트(16진수)ASCII 표현오프셋
PNG.png89 50 4E 47 0D 0A 1A 0A‰PNG\r\n\x1a\n0
JPEG.jpg/.jpegFF D8 FF0
GIF87a.gif47 49 46 38 37 61GIF87a0
GIF89a.gif47 49 46 38 39 61GIF89a0
WebP.webp52 49 46 46 ?? ?? ?? ?? 57 45 42 50RIFF????WEBP0
BMP.bmp42 4DBM0
TIFF(리틀 엔디언).tiff/.tif49 49 2A 00II*\00
TIFF(빅 엔디언).tiff/.tif4D 4D 00 2AMM\0*0
AVIF / HEIF.avif/.heif66 74 79 70ftyp4
ICO.ico00 00 01 000
SVG.svg<?xml 또는 <svg텍스트0(BOM 없음)

문서·아카이브

형식확장자매직 바이트(16진수)비고
PDF.pdf25 50 44 46 2D%PDF-
ZIP.zip50 4B 03 04PK\x03\x04
ZIP(빈 파일).zip50 4B 05 06
GZIP.gz1F 8B
7-Zip.7z37 7A BC AF 27 1C7z\xBC\xAF'\x1C
RAR4.rar52 61 72 21 1A 07 00Rar!\x1A\x07\x00
RAR5.rar52 61 72 21 1A 07 01 00
TAR.tar75 73 74 61 72ustar(오프셋 257)
DOCX / XLSX / PPTX.docx 등50 4B 03 04ZIP 기반(확장자로 구분)
XLS(구형식).xlsD0 CF 11 E0 A1 B1 1A E1OLE2 컨테이너
DOC(구형식).docD0 CF 11 E0 A1 B1 1A E1OLE2 컨테이너

텍스트·데이터 형식

형식확장자매직 바이트 / BOM비고
UTF-8 BOM 있음.txt/.csv 등EF BB BFBOM(Byte Order Mark)
UTF-16 LE BOM.txt 등FF FE리틀 엔디언
UTF-16 BE BOM.txt 등FE FF빅 엔디언
UTF-32 LE BOM.txt 등FF FE 00 00
JSON(일반).json7B 또는 5B{ 또는 [
CSV(일반).csv텍스트(BOM 없음)시그니처 없음
XML.xml3C 3F 78 6D 6C<?xml

음성·동영상

형식확장자매직 바이트(16진수)비고
MP3.mp3FF FB / FF F3 / FF F2또는 ID3 태그: 49 44 33
MP4 / M4A / M4V.mp4 등66 74 79 70ftyp(오프셋 4)
WAV.wav52 49 46 46 ?? ?? ?? ?? 57 41 56 45RIFF????WAVE
OGG.ogg/.ogv4F 67 67 53OggS
FLAC.flac66 4C 61 43fLaC
AVI.avi52 49 46 46 ?? ?? ?? ?? 41 56 49 20RIFF????AVI
MKV / WebM.mkv/.webm1A 45 DF A3EBML 헤더

실행 파일·기타

형식확장자매직 바이트(16진수)비고
ELF(Linux 실행 파일)없음/.elf7F 45 4C 46\x7FELF
PE(Windows 실행 파일).exe/.dll4D 5AMZ
Mach-O(macOS 실행 파일)없음CF FA ED FE64bit
PHP 스크립트.php3C 3F 70 68 70<?php
SQLite.sqlite/.db53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00SQLite format 3\0
ISO.iso43 44 30 30 31오프셋 32769: CD001

PHP에서의 매직 바이트 검증 구현 예

 ['offset' => 0, 'bytes' => "\x89PNG\r\n\x1a\n", 'length' => 8],
        'jpg'  => ['offset' => 0, 'bytes' => "\xFF\xD8\xFF",       'length' => 3],
        'gif'  => ['offset' => 0, 'bytes' => "GIF8",               'length' => 4],
        'pdf'  => ['offset' => 0, 'bytes' => "%PDF-",              'length' => 5],
        'zip'  => ['offset' => 0, 'bytes' => "PK\x03\x04",         'length' => 4],
        'exe'  => ['offset' => 0, 'bytes' => "MZ",                 'length' => 2],
    ];

    if (!isset($signatures[$expectedType])) {
        throw new \InvalidArgumentException("알 수 없는 파일 형식: $expectedType");
    }

    $sig = $signatures[$expectedType];
    $handle = fopen($filePath, 'rb');
    if ($sig['offset'] > 0) fseek($handle, $sig['offset']);
    $header = fread($handle, $sig['length']);
    fclose($handle);

    if (substr($header, 0, $sig['length']) !== $sig['bytes']) {
        throw new \RuntimeException("매직 바이트가 일치하지 않습니다 (기대: $expectedType)");
    }
}

// 사용 예
validateMagicBytes($_FILES['upload']['tmp_name'], 'png');
echo "올바른 PNG 파일입니다";

관련 자료

❓ 자주 묻는 질문

확장자 검사만으로는 안 되는 이유는?
확장자는 파일 이름의 일부일 뿐이고 공격자가 자유롭게 바꿔 붙일 수 있기 때문입니다. shell.php 를 shell.jpg 로 이름만 바꾸면 확장자 검사는 통과합니다. 매직 바이트는 실제 데이터 선두를 보므로 개명으로는 속일 수 없습니다. 다만 이것도 선두 몇 바이트를 위장한 다중 형식 파일에는 약하므로 확장자, MIME, 매직 바이트 세 가지로 대조하세요.
PNG 와 JPEG 의 시그니처는 몇 바이트 읽으면 판정할 수 있나요?
PNG 는 8 바이트(89 50 4E 47 0D 0A 1A 0A), JPEG 는 선두 3 바이트(FF D8 FF)로 판정할 수 있습니다. 구현상 선두 12 바이트 정도 읽어 두면 주요 형식을 한꺼번에 판별할 수 있고 ZIP(50 4B 03 04)과 PDF(25 50 44 46)도 이 범위에 들어갑니다. 파일 전체를 메모리에 올릴 필요는 없습니다.
Office 문서나 APK 가 ZIP 으로 판정됩니다.
올바른 판정입니다. docx, xlsx, pptx, APK, JAR, EPUB 은 모두 ZIP 컨테이너이며 선두가 50 4B 03 04 입니다. 구별하려면 압축을 풀어 내용을 봐야 하고 docx 라면 [Content_Types].xml, APK 라면 AndroidManifest.xml 의 유무로 판정합니다. 매직 바이트만으로 docx 를 허용하고 APK 를 막을 수는 없습니다.