접두사 표
각 행은 해당 형식의 실제 매직 바이트를 인코딩해 확인했습니다. 여기 실린 접두사는 그 형식에서 절대 바뀌지 않는 부분이며, 그 뒤의 문자는 파일의 나머지 내용에 따라 달라집니다.
| Base64 접두사 | 매직 바이트 (hex) | 형식 | 여는 도구 |
|---|---|---|---|
iVBORw0KGgo | 89 50 4E 47 0D 0A 1A 0A | PNG | Base64를 PNG로 |
/9j/ | FF D8 FF | JPEG | Base64를 JPG로 |
R0lGOD | 47 49 46 38 (GIF8) | GIF (R0lGODlh = GIF89a, R0lGODdh = GIF87a) | Base64를 GIF로 |
UklGR | 52 49 46 46 (RIFF) | WebP, WAV, AVI | Base64를 WebP로, Base64를 WAV로 |
JVBERi0 | 25 50 44 46 2D (%PDF-) | Base64를 PDF로 | |
UEsDB | 50 4B 03 04 (PK..) | ZIP, DOCX, XLSX, PPTX, JAR, APK, EPUB | Base64를 ZIP으로, Word, Excel |
H4sI | 1F 8B 08 | gzip | gzip Base64 디코딩 |
eJ, eN, eF, eA | 78 9C, 78 DA, 78 5E, 78 01 | zlib | Zlib과 Base64 |
eyJ | 7B 22 ({") | JSON 객체, JWT | Base64를 JSON으로, JWT 디코더 |
PD94bWwg | 3C 3F 78 6D 6C 20 (<?xml ) | XML, 선언이 있는 SVG | Base64를 XML로 |
PHN2Zy | 3C 73 76 67 20 (<svg ) | 선언이 없는 SVG (<svg 뒤에 줄 바꿈이 오면 PHN2Zw) | Base64를 SVG로 |
MII | 30 82 | DER: 인증서, 키, CSR | 인증서 디코더 |
AAAA | 00 00 00 | SSH 공개 키 데이터, 또는 앞쪽의 0 | SSH 키 지문 |
SUQz | 49 44 33 (ID3) | ID3v2 태그가 있는 MP3 | Base64를 MP3로 |
AAABAA | 00 00 01 00 | ICO | Base64를 ICO로 |
d09GMg | 77 4F 46 32 00 (wOF2) | TrueType 윤곽선을 쓰는 WOFF2 글꼴 (CFF 글꼴은 d09GMk9UVE8로 시작) | Base64를 글꼴로 |
TVqQ | 4D 5A 90 (MZ) | Windows EXE 또는 DLL (일부 링커는 MZP를 써서 TVpQ가 됨) | Base64를 파일로 |
f0VMR | 7F 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를 파일로 도구는 데이터를 디코딩한 뒤 그 바이트를 많은 시그니처와 비교합니다.