이메일 이미지가 안 보이는 이유가 Base64였다 — 인코딩 원리부터 실무 함정까지 2026
btoa()가 이모지에서 터지는 이유, JWT가 Base64를 쓰는 이유, 표준 Base64와 URL-safe Base64를 헷갈리면 생기는 일. 웰컴 이메일 프로필 사진 깨짐 버그 실화에서 시작하는 Base64 실전 가이드.
오전 9시에 버그 리포트가 들어왔어요. '웰컴 이메일에 프로필 사진이 안 뜬다'는 거예요. 엔지니어 넷이서 90분을 CDN 캐싱 문제로 추정하고 뒤졌는데 아무것도 없었어요. 누군가 MIME 원문을 Base64 디코더에 돌렸더니 바로 나왔어요. 백엔드에서 UTF-8 문자열에 btoa()를 돌리고 있었던 거예요. Latin1 범위를 벗어나는 한글 이름, 이모지가 들어간 닉네임 — 전부 조용히 깨져 있었어요. Base64를 제대로 알았으면 코드 리뷰 20분에 잡을 수 있었던 버그예요.
이 글에서 알 수 있는 것
- ✅3바이트 → 4문자 변환이 실제로 어떻게 동작하는지, 왜 출력이 항상 33% 더 큰지
- ✅표준 Base64와 URL-safe Base64 차이 — 이걸 헷갈리면 JWT가 깨지는 이유
- ✅btoa()가 유니코드에서 터지는 이유와 해결법, 도구별 비교
Base64가 실제로 하는 일
Base64는 바이너리 데이터를 64개의 안전한 ASCII 문자로 변환하는 인코딩 방식이에요. 원래 설계 목적은 이메일(SMTP)처럼 7비트 ASCII만 처리하는 텍스트 전용 시스템에서 바이너리 파일을 안전하게 보내는 거였어요.
- 3바이트(24비트)씩 처리해요 — 3바이트를 6비트짜리 네 덩어리로 쪼개요
- 각 6비트 값을 64개의 출력 가능한 ASCII 문자 중 하나로 매핑해요 (A-Z, a-z, 0-9, +, /)
- 출력은 항상 입력보다 정확히 33% 더 커요 — 텍스트 안전 인코딩의 비용이에요
- 입력 길이가 3으로 나누어지지 않으면 = 패딩 문자로 빈 자리를 채워요
실제 코드에서 Base64가 나오는 곳
Base64는 한 가지가 아니에요. 맥락마다 조금씩 다른 방식으로 나타나요. 어떤 변형인지 알아야 디버깅할 때 시간을 아낄 수 있어요.
- 이메일 첨부파일(MIME): SMTP는 7비트 ASCII 텍스트 전용이에요. PDF를 첨부할 때 메일 클라이언트가 자동으로 Base64 인코딩을 해줘요.
- HTML/CSS Data URI: data:image/png;base64,...로 이미지를 마크업에 직접 임베딩해요. HTTP 요청을 줄이는 대신 33% 용량 증가와 캐싱 포기를 감수해야 해요.
- API 페이로드(JSON): JSON은 텍스트 전용이에요. 이미지, 오디오, PDF를 JSON 바디에 넣으려면 Base64로 인코딩해야 해요.
- JWT 토큰: 점(.)으로 구분된 JWT 세 부분이 전부 URL-safe Base64예요. 헤더, 페이로드, 서명이 각각 그 방식으로 인코딩돼 있어요.
- HTTP Basic 인증: Authorization 헤더에 들어가는 username:password 조합이 Base64 인코딩된 거예요. 암호화가 아니에요.
HTTP Basic Auth의 Base64는 보안이 아니에요
Authorization: Basic dXNlcjpwYXNz를 디코딩하면 즉시 user:pass가 나와요. Base64는 암호화가 아니거든요. Basic Auth를 쓸 거라면 반드시 HTTPS 위에서만 써야 하고, 가능하면 토큰 기반 인증으로 바꾸는 게 나아요.
표준 Base64 vs URL-safe Base64 — 혼용하면 생기는 일
| 속성 | 표준 Base64 | URL-safe Base64 (base64url) |
|---|---|---|
| 문자셋 | A-Z, a-z, 0-9, +, / | A-Z, a-z, 0-9, -, _ |
| 패딩 | = 문자 사용 | 패딩 생략 |
| URL에서 안전? | 아니요 — +와 /가 URL 예약 문자 | 네 — URL 전용으로 설계됨 |
| 사용 위치 | 이메일(MIME), data URI, 일반 인코딩 | JWT 토큰, OAuth, URL 파라미터 |
이 둘을 혼용하면 버그가 나요. 표준 Base64로 인코딩한 걸 URL에 넣으면 +가 공백으로 디코딩되고, /가 경로 구분자로 해석돼요. URL이나 HTTP 헤더에 들어가는 건 항상 URL-safe Base64를 써야 해요.
btoa()가 유니코드에서 터지는 이유와 해결법
JavaScript 내장 btoa() 함수는 Latin1 문자만 처리해요. 한글, 이모지, 유니코드 문자를 넘기면 'The string to be encoded contains characters outside of the Latin1 range' 에러를 던져요. 이게 웰컴 이메일 버그의 원인이에요. UTF-8로 먼저 인코딩하는 과정이 필요해요:
// 틀린 방법 — Latin1 범위 밖 문자에서 실패
btoa('안녕하세요') // DOMException 발생
// 맞는 방법 — 전체 UTF-8 처리
function base64Encode(str) {
return btoa(
Array.from(new TextEncoder().encode(str))
.map(byte => String.fromCharCode(byte))
.join('')
);
}
function base64Decode(b64) {
return new TextDecoder().decode(
Uint8Array.from(atob(b64), c => c.charCodeAt(0))
);
}도구 비교: btoa() vs 터미널 vs QuickFigure
| 도구 | UTF-8 지원 | URL-safe 모드 | 이미지 인코딩 | 오프라인 |
|---|---|---|---|---|
| btoa()/atob() | 아니요 (Latin1만) | 아니요 | 아니요 | 네 |
| 터미널 (base64) | 네 | 아니요 (수동) | 네 (파일 경로로) | 네 |
| QuickFigure | 네 | 네 (토글) | 네 (드래그앤드롭) | 네 (브라우저) |
Base64는 인코딩이에요, 암호화가 아니에요 — 민감한 데이터를 숨기는 데 쓰지 마세요
Base64가 뒤죽박죽 문자열처럼 보여도 보안이 전혀 없어요. 누구나 즉시 디코딩할 수 있어요. 클라이언트 코드, localStorage, URL 파라미터에 Base64로 인코딩한 비밀번호나 API 키를 넣는 건 평문으로 저장하는 것과 같아요. 실제 보안이 필요하다면 암호화(AES-256), 안전한 스토리지 API, 또는 서버 사이드 보안을 써야 해요.
자주 묻는 질문
Base64는 암호화인가요?
아니요. Base64는 인코딩이지 암호화가 아니에요. 알려진 알고리즘으로 바이너리 데이터를 텍스트로 변환하는 거라서 누구나 즉시 디코딩할 수 있어요. 민감한 정보를 보호하는 데 절대 쓰면 안 돼요. 보안에는 암호화(데이터 보호에 AES-256, 전송에 TLS)를 써야 해요.
왜 Base64 출력이 항상 입력보다 큰가요?
Base64는 3바이트를 4문자로 변환해요. 8비트 대신 6비트씩 쓰는 거라서요. 3바이트가 4바이트로 — 약 33% 증가가 생겨요. 100KB 이미지는 Base64로 133KB가 돼요. 이건 바이너리를 텍스트로 안전하게 표현할 때 피할 수 없는 비용이에요.
모든 파일 종류를 Base64로 인코딩할 수 있나요?
네. 이미지, PDF, 오디오, 실행 파일, 압축 파일 — 바이너리면 전부 가능해요. 10KB 이하 아이콘이나 로고는 data URI로 쓰는 게 합리적이에요. 더 큰 파일은 33% 오버헤드와 캐싱 불가 문제 때문에 외부 파일 호스팅이 나아요.
끝에 붙는 = 패딩은 무슨 의미예요?
Base64는 3바이트씩 처리해요. 입력이 3으로 나누어지지 않으면 출력을 4의 배수로 맞추려고 = 문자를 추가해요. = 하나는 1바이트 패딩, == 두 개는 2바이트 패딩이에요. URL-safe Base64는 패딩을 아예 생략해요.
Base64 인코더/디코더
텍스트나 파일을 Base64로 인코딩하거나 디코딩하세요. UTF-8 완전 지원, URL-safe 토글, 이미지 드래그앤드롭. 모든 처리가 브라우저에서 이루어져요.
Base64 도구 열기 →▶이 글에서 다룬 도구 바로 사용하기
민재
개발자 겸 테크 라이터. 개발 도구와 파일 변환 기술을 깊이 있게 다룹니다.
이 글이 도움이 되셨나요? 새 가이드 알림 받기
스팸 없이, 새 소식만 보내드립니다. 언제든 취소 가능. · 구독 시 개인정보처리방침에 동의합니다.