파일 업로드
  1. base64hub
  2. Base64 가이드
  3. 자주 보는 Base64 접두사
레퍼런스

자주 보는 Base64 접두사: 시작 부분으로 파일 알아보기

대부분의 파일 형식은 고정된 매직 바이트로 시작하므로, 그 Base64도 고정된 문자로 시작합니다. 접두사 열두어 개만 익혀 두면 디코딩하기 전에 PNG와 PDF를 구분할 수 있습니다.

접두사 표

각 행은 해당 형식의 실제 매직 바이트를 인코딩해 확인했습니다. 여기 실린 접두사는 그 형식에서 절대 바뀌지 않는 부분이며, 그 뒤의 문자는 파일의 나머지 내용에 따라 달라집니다.

Base64 접두사매직 바이트 (hex)형식여는 도구
iVBORw0KGgo89 50 4E 47 0D 0A 1A 0APNGBase64를 PNG로
/9j/FF D8 FFJPEGBase64를 JPG로
R0lGOD47 49 46 38 (GIF8)GIF (R0lGODlh = GIF89a, R0lGODdh = GIF87a)Base64를 GIF로
UklGR52 49 46 46 (RIFF)WebP, WAV, AVIBase64를 WebP로, Base64를 WAV로
JVBERi025 50 44 46 2D (%PDF-)PDFBase64를 PDF로
UEsDB50 4B 03 04 (PK..)ZIP, DOCX, XLSX, PPTX, JAR, APK, EPUBBase64를 ZIP으로, Word, Excel
H4sI1F 8B 08gzipgzip Base64 디코딩
eJ, eN, eF, eA78 9C, 78 DA, 78 5E, 78 01zlibZlib과 Base64
eyJ7B 22 ({")JSON 객체, JWTBase64를 JSON으로, JWT 디코더
PD94bWwg3C 3F 78 6D 6C 20 (<?xml )XML, 선언이 있는 SVGBase64를 XML로
PHN2Zy3C 73 76 67 20 (<svg )선언이 없는 SVG (<svg 뒤에 줄 바꿈이 오면 PHN2Zw)Base64를 SVG로
MII30 82DER: 인증서, 키, CSR인증서 디코더
AAAA00 00 00SSH 공개 키 데이터, 또는 앞쪽의 0SSH 키 지문
SUQz49 44 33 (ID3)ID3v2 태그가 있는 MP3Base64를 MP3로
AAABAA00 00 01 00ICOBase64를 ICO로
d09GMg77 4F 46 32 00 (wOF2)TrueType 윤곽선을 쓰는 WOFF2 글꼴 (CFF 글꼴은 d09GMk9UVE8로 시작)Base64를 글꼴로
TVqQ4D 5A 90 (MZ)Windows EXE 또는 DLL (일부 링커는 MZP를 써서 TVpQ가 됨)Base64를 파일로
f0VMR7F 45 4C 46 (.ELF)Linux ELF 바이너리Base64를 파일로

몇몇 행은 설명이 필요합니다.

  • RIFF는 컨테이너입니다. 형식 이름은 8–11번째 바이트에 있고, 9–11번째 바이트는 13–16번째 문자로 인코딩됩니다. WebP(EBP)는 RUJQ, WAV(AVE)는 QVZF, AVI(VI )는 Vkkg입니다. 형식 이름의 첫 글자는 파일 크기와 같은 3바이트 묶음에 들어가므로 고정된 문자가 나오지 않습니다.
  • zlib에는 하나로 정해진 접두사가 없습니다. 두 번째 바이트가 압축 수준을 기록합니다. 기본 수준은 eJ, 7–9는 eN, 2–5는 eF, 0과 1은 eA입니다(Python의 zlib 기준).
  • JSON은 처음 두 문자가 공백 없는 {"일 때만 eyJ로 시작합니다. { "a": 1 }은 eyAi로, 보기 좋게 정렬해 { 뒤에 줄 바꿈이 온 JSON은 ewo로, 배열 [는 W로 시작합니다.
  • DER 구조는 SEQUENCE 태그 30으로 시작하며, 이는 항상 M이 됩니다. 2바이트 길이(30 82)는 MII가 되고, 다음 문자는 길이를 따라갑니다. RSA 2048 공개 키는 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA, 흔한 인증서는 MIIC, MIID, MIIE입니다. 짧은 구조는 1바이트 길이를 씁니다. Ed25519 개인 키는 MC4C로, P-256 공개 키는 MFkw로 시작합니다.
  • SSH 공개 키는 4바이트 빅 엔디언 길이로 시작하므로 데이터가 AAAA로 시작합니다. 그다음 문자가 키 유형을 나타냅니다. AAAAC3NzaC1lZDI1NTE5는 ssh-ed25519, AAAAB3NzaC1yc2E는 ssh-rsa, AAAAE2VjZHNh는 ecdsa입니다. SSH가 아니라면 A가 이어지는 것은 그냥 0 바이트라는 뜻입니다.
  • MP3 파일에 ID3 태그가 없으면 프레임 헤더로 바로 시작합니다. 동기 비트 FF Fx 때문에 앞에 //가 오며, 예를 들어 FF FB 90은 //uQ입니다.
  • Base64URL은 +와 /를 바꾸므로 JPEG 접두사가 _9j_가 됩니다. 표의 다른 접두사에는 두 문자가 없어서 두 알파벳에서 똑같아 보입니다.

접두사가 고정되는 이유

Base64는 3바이트 묶음 단위로 동작합니다. 3바이트 묶음은 정확히 4자가 되고, 그 4자는 그 3바이트에만 좌우됩니다. 파일 뒤쪽의 내용이 앞으로 새어 나오지 않습니다. 그래서 어떤 형식이 항상 같은 3바이트로 시작한다면, 그 Base64는 항상 같은 4자로 시작합니다.

bytes:   FF       D8       FF
bits:    11111111 11011000 11111111
groups:  111111 111101 100011 111111
index:   63     61     35     63
chars:   /      9      j      /

고정된 매직 바이트의 길이가 3의 배수가 아니면, 마지막 묶음에 알려진 비트와 파일 나머지의 비트가 섞입니다. 5바이트 %PDF-를 예로 들어 보겠습니다. 처음 3바이트는 고정된 4자(JVBE)가 됩니다. 다음 2바이트는 2자(Ri)를 더하고, 일곱 번째 문자에는 -의 마지막 4비트와 버전 숫자의 처음 2비트가 섞입니다. 숫자는 모두 비트 00으로 시작하므로 실제로 이 문자는 항상 0입니다. JVBERi0 뒤로는 버전이 드러납니다. JVBERi0xLjQ는 %PDF-1.4, JVBERi0xLjc는 %PDF-1.7, JVBERi0yLjA는 %PDF-2.0입니다.

PNG 시그니처는 8바이트로, 고정된 문자 10개가 됩니다. 열한 번째 문자에는 시그니처의 마지막 바이트와 항상 0인 IHDR 청크 길이의 첫 바이트가 섞이므로 iVBORw0KGgo가 유지됩니다. 모든 PNG는 그 IHDR 청크로 이어지므로 실제 PNG는 더 긴 접두사 iVBORw0KGgoAAAANSUhEUg를 공유합니다.

접두사가 밀릴 때

접두사는 매직 바이트가 오프셋 0, 3, 6 같은 위치에 있을 때만 통합니다. 앞에 바이트 하나를 더하면 모든 묶음이 밀려서 문자가 완전히 바뀝니다.

입력Base64 시작 부분
PNG 시그니처iVBORw0KGgoAAAA
1바이트 + PNG 시그니처AIlQTkcNChoKAAAA
2바이트 + PNG 시그니처AACJUE5HDQoaCgAA
3바이트 + PNG 시그니처AAAAiVBORw0KGgoA

여분의 바이트가 3개면 정렬이 회복되어 익숙한 접두사가 4자 뒤에 다시 나타납니다. 접두사가 밀리거나 사라지는 흔한 이유는 다음과 같습니다.

  • 바이트 순서 표시(BOM). BOM이 있는 UTF-8 텍스트는 77u/(EF BB BF)로 시작합니다. BOM은 3바이트이므로 그 뒤의 JSON은 여전히 eyJ로 보입니다: 77u/eyJ…. BOM이 있는 UTF-16 텍스트는 //4나 //5(리틀 엔디언), 또는 /v8(빅 엔디언)로 시작합니다.
  • UTF-16 텍스트. UTF-16LE로 저장한 텍스트는 ASCII 문자마다 뒤에 0 바이트를 넣으므로 A가 많이 나옵니다. Hello는 SABlAGwAbABvAA==가 됩니다. PowerShell의 -EncodedCommand가 이렇게 생겼습니다. PowerShell 디코더나 Base64를 UTF-16으로를 쓰세요.
  • 압축이나 암호화. gzip으로 압축한 PNG는 H4sI로 시작하고, 암호화된 파일에는 알아볼 수 있는 접두사가 전혀 없습니다.
  • data URI. data:image/png;base64,는 헤더이며, Base64는 쉼표 뒤에서 시작합니다. data URI 파서가 둘을 나눠 줍니다.
  • 줄 바꿈과 공백. 바이트를 밀지는 않지만, 문자열이 줄 바꿈이나 따옴표로 시작하면 startswith로 하는 접두사 검색이 실패합니다. 먼저 공백을 정리하거나 Base64 복구를 거치세요.

코드에서 접두사 확인하기

첫 문자를 문자열로 비교할 수도 있지만, 디코딩한 바이트를 비교하는 편이 실수가 적습니다. 매직 넘버는 각 형식의 명세에서 바로 가져오면 되고, 어떤 문자가 고정되는지 따져 볼 필요가 없습니다. 처음 12자만 디코딩해도 처음 9바이트가 나오며, 대부분의 시그니처에는 이것으로 충분합니다.

import base64

SIGNATURES = {
    b"\x89PNG\r\n\x1a\n": "png",
    b"\xff\xd8\xff": "jpeg",
    b"%PDF-": "pdf",
    b"PK\x03\x04": "zip",
    b"\x1f\x8b": "gzip",
}

def sniff(b64: str) -> str:
    head = base64.b64decode(b64.strip()[:12])
    for magic, name in SIGNATURES.items():
        if head.startswith(magic):
            return name
    return "unknown"

print(sniff("iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB"))  # png
print(sniff("JVBERi0xLjcKJcfsj6IK"))              # pdf

Base64를 파일로 도구는 더 긴 목록으로 같은 검사를 하고, 브라우저가 렌더링할 수 있는 형식이면 미리보기를 보여 줍니다. 6비트 묶음이 문자에 대응하는 방식은 Base64의 원리와 알파벳 표를 참고하세요.

자주 묻는 질문

iVBORw0KGgo로 시작하는 Base64 문자열은 무엇인가요?

PNG 이미지입니다. iVBORw0KGgo는 8바이트 PNG 시그니처 89 50 4E 47 0D 0A 1A 0A의 Base64 형태입니다. Base64를 PNG로에 붙여넣어 확인하세요.

Base64 문자열 앞의 /9j/는 무엇인가요?

JPEG입니다. 모든 JPEG 파일을 여는 바이트 FF D8 FF가 /9j/로 인코딩됩니다. Base64URL에서는 같은 접두사가 _9j_로 쓰입니다.

JWT는 왜 항상 eyJ로 시작하나요?

JWT 헤더는 JSON 객체이므로 {"로 시작하고, 이 두 바이트가 eyJ로 인코딩됩니다. 페이로드 부분도 같은 이유로 eyJ로 시작합니다.

제 Base64가 아는 접두사 어디에도 해당하지 않습니다. 어떻게 하나요?

데이터 앞에 여분의 바이트가 있거나, 압축 또는 암호화되었거나, 그냥 텍스트일 수 있습니다. Base64를 파일로 도구는 데이터를 디코딩한 뒤 그 바이트를 많은 시그니처와 비교합니다.

계속 읽기