Dev
Base64 인코딩의 모든 것 - 원리부터 실전 활용까지
Base64 인코딩이 무엇인지, 왜 필요한지, 어떻게 사용하는지 실전 예제와 함께 완벽하게 알아봅니다. 이미지 인라인 삽입부터 JWT까지.
Toolypet Team
Development Team
Base64 인코딩의 모든 것
"이 이미지를 API로 어떻게 보내죠?" "이 바이너리 데이터를 JSON에 어떻게 넣죠?"
답은 Base64입니다.
이 가이드에서는 Base64의 원리부터 실전 활용까지 완벽하게 다룹니다.
Base64란?
Base64는 바이너리 데이터를 텍스트로 변환하는 인코딩 방식입니다.
왜 필요한가?
| 문제 | Base64 해결책 |
|---|---|
| 이메일로 바이너리 전송 불가 | 텍스트로 변환하여 전송 |
| JSON에 바이너리 포함 불가 | 문자열로 변환하여 포함 |
| URL에 특수문자 불가 | URL-safe 문자만 사용 |
| HTML에 이미지 인라인 삽입 | Data URL로 변환 |
특징
- 64개 문자 사용: A-Z, a-z, 0-9, +, / (표준)
- 크기 증가: 원본 대비 약 33% 증가
- 가역적: 인코딩 ↔ 디코딩 완벽 복원
- 암호화 아님: 누구나 디코딩 가능
Base64 원리
인코딩 과정
원본 문자열: "Man"
1. ASCII 변환
M = 77 = 01001101
a = 97 = 01100001
n = 110 = 01101110
2. 6비트씩 분할
010011 | 010110 | 000101 | 101110
19 | 22 | 5 | 46
3. Base64 문자로 변환 (A=0, B=1, ... Z=25, a=26, ...)
19 = T
22 = W
5 = F
46 = u
결과: "TWFu"
Base64 문자표
인덱스: 문자
0-25: A-Z
26-51: a-z
52-61: 0-9
62: +
63: /
패딩: =
패딩 (=)
원본 길이가 3으로 나누어 떨어지지 않으면 패딩 추가
"M" → "TQ==" (2개 패딩)
"Ma" → "TWE=" (1개 패딩)
"Man" → "TWFu" (패딩 없음)
언어별 구현
JavaScript (브라우저)
// 인코딩
const encoded = btoa('Hello, World!');
console.log(encoded); // "SGVsbG8sIFdvcmxkIQ=="
// 디코딩
const decoded = atob('SGVsbG8sIFdvcmxkIQ==');
console.log(decoded); // "Hello, World!"
// 유니코드 처리 (한글 등)
function encodeUnicode(str) {
return btoa(encodeURIComponent(str).replace(
/%([0-9A-F]{2})/g,
(_, p1) => String.fromCharCode(parseInt(p1, 16))
));
}
function decodeUnicode(str) {
return decodeURIComponent(
Array.from(atob(str), c =>
'%' + c.charCodeAt(0).toString(16).padStart(2, '0')
).join('')
);
}
// 유니코드 테스트
const korean = '안녕하세요';
const encodedKorean = encodeUnicode(korean);
console.log(encodedKorean); // "7JWI64WVIQ=="
console.log(decodeUnicode(encodedKorean)); // "안녕하세요"
Node.js
// Buffer 사용
const encoded = Buffer.from('Hello, World!').toString('base64');
console.log(encoded); // "SGVsbG8sIFdvcmxkIQ=="
const decoded = Buffer.from('SGVsbG8sIFdvcmxkIQ==', 'base64').toString('utf-8');
console.log(decoded); // "Hello, World!"
// 파일 인코딩
const fs = require('fs');
const imageBuffer = fs.readFileSync('image.png');
const base64Image = imageBuffer.toString('base64');
console.log(base64Image.substring(0, 50) + '...');
Python
import base64
# 인코딩
encoded = base64.b64encode(b'Hello, World!').decode('utf-8')
print(encoded) # "SGVsbG8sIFdvcmxkIQ=="
# 디코딩
decoded = base64.b64decode('SGVsbG8sIFdvcmxkIQ==').decode('utf-8')
print(decoded) # "Hello, World!"
# 유니코드 (한글)
korean = '안녕하세요'
encoded_korean = base64.b64encode(korean.encode('utf-8')).decode('utf-8')
print(encoded_korean) # "7JWI64WVIQ=="
# 파일 인코딩
with open('image.png', 'rb') as f:
base64_image = base64.b64encode(f.read()).decode('utf-8')
Go
package main
import (
"encoding/base64"
"fmt"
)
func main() {
// 인코딩
data := "Hello, World!"
encoded := base64.StdEncoding.EncodeToString([]byte(data))
fmt.Println(encoded) // "SGVsbG8sIFdvcmxkIQ=="
// 디코딩
decoded, _ := base64.StdEncoding.DecodeString(encoded)
fmt.Println(string(decoded)) // "Hello, World!"
// URL-safe Base64
urlSafe := base64.URLEncoding.EncodeToString([]byte(data))
fmt.Println(urlSafe)
}
실전 활용
1. 이미지 인라인 삽입 (Data URL)
<!-- HTML에서 직접 이미지 삽입 -->
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" alt="1x1 red pixel">
// 파일 → Base64 Data URL
function fileToDataUrl(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(file);
});
}
// 사용
const file = document.getElementById('fileInput').files[0];
const dataUrl = await fileToDataUrl(file);
document.getElementById('preview').src = dataUrl;
2. API로 이미지 전송
// 클라이언트
async function uploadImage(file) {
const base64 = await fileToBase64(file);
const response = await fetch('/api/upload', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
filename: file.name,
contentType: file.type,
data: base64,
}),
});
return response.json();
}
function fileToBase64(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
// data:image/png;base64, 접두사 제거
const base64 = reader.result.split(',')[1];
resolve(base64);
};
reader.onerror = reject;
reader.readAsDataURL(file);
});
}
// 서버 (Node.js)
app.post('/api/upload', (req, res) => {
const { filename, contentType, data } = req.body;
// Base64 → Buffer → 파일 저장
const buffer = Buffer.from(data, 'base64');
fs.writeFileSync(`uploads/${filename}`, buffer);
res.json({ success: true, filename });
});
3. JWT 토큰
// JWT = Header.Payload.Signature (각각 Base64URL 인코딩)
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
// Payload 디코딩
const payload = token.split('.')[1];
const decoded = JSON.parse(atob(payload));
console.log(decoded);
// { sub: "1234567890", name: "John Doe", iat: 1516239022 }
4. Basic 인증
// HTTP Basic Authentication
const username = 'user';
const password = 'password';
const credentials = btoa(`${username}:${password}`);
fetch('/api/protected', {
headers: {
'Authorization': `Basic ${credentials}`,
},
});
// 헤더: Authorization: Basic dXNlcjpwYXNzd29yZA==
5. 이메일 첨부파일 (MIME)
Content-Type: application/pdf
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="document.pdf"
JVBERi0xLjQKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIK
Pj4KZW5kb2JqCjIgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFszIDAgUl0K
...
Base64 변형
URL-safe Base64
| 표준 | URL-safe |
|---|---|
+ | - |
/ | _ |
= | 생략 가능 |
// URL-safe 인코딩
function toUrlSafeBase64(str) {
return btoa(str)
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
// URL-safe 디코딩
function fromUrlSafeBase64(str) {
// 패딩 복원
const pad = str.length % 4;
const padded = pad ? str + '='.repeat(4 - pad) : str;
return atob(
padded
.replace(/-/g, '+')
.replace(/_/g, '/')
);
}
Base64 vs Base32 vs Base16
| 인코딩 | 문자 수 | 크기 증가 | 사용 사례 |
|---|---|---|---|
| Base64 | 64 | +33% | 일반적 |
| Base32 | 32 | +60% | 대소문자 미구분 필요 시 |
| Base16 (Hex) | 16 | +100% | 해시, 색상 코드 |
주의사항
1. 암호화가 아님
// ❌ 보안 목적으로 사용하면 안 됨
const password = btoa('mySecretPassword');
// 누구나 atob()으로 복원 가능!
// ✅ 암호화가 필요하면 별도 암호화 후 Base64
const encrypted = await encryptAES(data, key);
const encoded = btoa(encrypted);
2. 크기 증가
// 원본: 1MB 이미지
// Base64: ~1.33MB (33% 증가)
// 대용량 파일은 직접 업로드가 효율적
// FormData + multipart/form-data 사용
3. 유니코드 처리
// ❌ 브라우저 btoa()는 Latin-1만 지원
btoa('한글'); // Error: The string contains characters outside of the Latin1 range
// ✅ 유니코드 처리 필요
function encodeUnicode(str) {
return btoa(unescape(encodeURIComponent(str)));
}
4. 줄바꿈
// 일부 시스템은 76자마다 줄바꿈 추가
// MIME 표준: 76자 줄바꿈
// 줄바꿈 제거
const cleaned = base64String.replace(/[\r\n]/g, '');
성능 최적화
스트리밍 인코딩
// 대용량 파일을 청크로 처리
async function* encodeFileInChunks(file, chunkSize = 1024 * 1024) {
const reader = file.stream().getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
// 청크 단위로 Base64 인코딩
yield Buffer.from(value).toString('base64');
}
}
웹 워커 활용
// worker.js
self.onmessage = function(e) {
const { action, data } = e.data;
if (action === 'encode') {
const result = btoa(data);
self.postMessage({ result });
}
};
// main.js
const worker = new Worker('worker.js');
worker.postMessage({ action: 'encode', data: largeString });
worker.onmessage = (e) => console.log(e.data.result);
디버깅 도구
Base64 Encoder/Decoder
- 텍스트 또는 파일 입력
- 인코딩/디코딩 버튼 클릭
- 결과 복사
CLI
# 인코딩
echo -n "Hello, World!" | base64
# SGVsbG8sIFdvcmxkIQ==
# 디코딩
echo "SGVsbG8sIFdvcmxkIQ==" | base64 -d
# Hello, World!
# 파일 인코딩
base64 image.png > image.txt
# 파일 디코딩
base64 -d image.txt > restored.png
FAQ
Q1: Base64는 왜 33% 커지나요?
A: 3바이트(24비트)를 4문자(4×6=24비트)로 표현하기 때문입니다.
- 3바이트 → 4문자
- 증가율: (4-3)/3 = 33%
Q2: 패딩(=)은 왜 필요한가요?
A: 디코더가 원본 길이를 알기 위해 필요합니다. 패딩 개수로 마지막 바이트 수를 추론합니다.
Q3: Base64URL은 언제 사용하나요?
A: URL이나 파일명에 사용할 때입니다. 표준 Base64의 +, /는 URL에서 특수 의미를 가지므로 -, _로 대체합니다.
Q4: 이미지 인라인 삽입의 장단점은?
A:
- 장점: HTTP 요청 감소, 캐싱 단순화
- 단점: HTML 크기 증가, 개별 이미지 캐싱 불가
- 권장: 작은 아이콘(2KB 이하)에만 사용
Q5: Base64 문자열인지 어떻게 확인하나요?
A: 정규식으로 형식 검사 후 디코딩 시도:
function isBase64(str) {
const regex = /^[A-Za-z0-9+/]*={0,2}$/;
if (!regex.test(str)) return false;
try {
atob(str);
return true;
} catch {
return false;
}
}
마무리
Base64 핵심 정리:
- 용도: 바이너리 → 텍스트 변환
- 크기: 원본 대비 33% 증가
- 보안: 암호화 아님 (누구나 디코딩 가능)
- 변형: URL-safe는
-,_사용 - 활용: Data URL, JWT, Basic Auth, MIME
관련 도구
| 도구 | 용도 |
|---|---|
| Base64 Encoder/Decoder | Base64 인코딩/디코딩 |
| JWT Decoder | JWT 토큰 분석 |
| JSON Formatter | JSON 포맷팅 |
Base64인코딩개발데이터APIJavaScript
저자 소개
Toolypet Team
Development Team
The Toolypet Team creates free, privacy-focused web tools for developers and designers. All tools run entirely in your browser with no data sent to servers.
Web DevelopmentCSS ToolsDeveloper ToolsSEOSecurity