Base64 인코딩 설명: 언제 어떻게 사용하는가

· 12분 읽기

목차

Base64 인코딩이란?

Base64는 바이너리 데이터를 ASCII 문자열로 변환하는 바이너리-텍스트 인코딩 방식입니다. A-Z, a-z, 0-9, +, /의 64개 출력 가능한 문자만 사용하여 바이너리 데이터를 표현하며, =는 패딩에 사용됩니다.

이 인코딩은 이메일, JSON API, XML 문서, HTML과 같은 텍스트 전용 채널을 통해 바이너리 데이터를 안전하게 전송할 수 있게 합니다. Base64가 없다면 바이너리 데이터는 텍스트를 예상하는 시스템에 의해 손상되거나 잘못 해석될 수 있습니다.

"Base64"라는 이름은 인코딩에 사용되는 64개 문자 알파벳에서 유래했습니다. 암호화나 해싱과 달리 Base64는 보안 수단이 아닙니다. 단순히 바이너리 데이터를 텍스트로 표현하는 방법입니다. 누구나 키나 비밀번호 없이 Base64를 원래 형태로 디코딩할 수 있습니다.

Base64는 현대 웹 개발의 모든 곳에 있습니다:

Base64를 언제 어떻게 사용하는지 이해하는 것은 웹 API, 데이터 전송 또는 파일 처리를 다루는 모든 개발자에게 기본적인 기술입니다.

Base64의 내부 작동 원리

인코딩 프로세스는 입력의 3바이트(24비트)를 4개의 Base64 문자(각 6비트)로 변환합니다. 이것이 Base64를 정의하는 핵심 수학적 관계입니다.

구체적인 예제와 함께 단계별 프로세스는 다음과 같습니다:

# 1단계: 3바이트 입력 가져오기
입력 텍스트: "Hi!"
바이너리: 01001000 01101001 00100001

# 2단계: 6비트 그룹으로 분할
010010 000110 100100 100001

# 3단계: 각 6비트 그룹을 Base64 알파벳에 매핑
010010 → S (18)
000110 → G (6)
100100 → k (36)
100001 → h (33)

# 결과: "Hi!" → "SGkh"

Base64 알파벳은 각 6비트 값(0-63)을 특정 문자에 매핑합니다:

값 범위 문자 설명
0-25 A-Z 대문자
26-51 a-z 소문자
52-61 0-9 숫자
62 + 더하기 기호
63 / 슬래시
- = 패딩 문자

패딩 이해하기

입력 길이가 3으로 나누어떨어지지 않을 때, Base64는 = 문자로 패딩을 추가하여 출력 길이를 4로 나누어떨어지게 만듭니다. 이는 적절한 디코딩을 보장합니다.

# 패딩 예제
"A"    → "QQ=="   (1바이트 → 2문자 + ==)
"AB"   → "QUI="   (2바이트 → 3문자 + =)
"ABC"  → "QUJD"   (3바이트 → 4문자, 패딩 없음)

패딩은 디코더에게 원본 입력에 몇 바이트가 있었는지 알려줍니다. 패딩이 없으면 디코더는 최종 그룹에 1, 2 또는 3바이트를 예상해야 하는지 알 수 없습니다.

전문가 팁: Base64는 항상 데이터 크기를 약 33% 증가시킵니다. 3바이트마다 4문자가 되므로 300KB 이미지는 Base64 인코딩 시 약 400KB가 됩니다.

문자당 6비트를 사용하는 이유는?

문자당 6비트를 선택한 것은 의도적입니다. 6비트로 2^6 = 64개의 서로 다른 값을 표현할 수 있으며, 이는 64개 문자 알파벳에 완벽하게 매핑됩니다.

이는 또한 3바이트(24비트)가 4개의 6비트 청크로 균등하게 나누어져 최소한의 오버헤드로 효율적인 인코딩 방식을 만든다는 것을 의미합니다.

실제 인코딩 및 디코딩

대부분의 프로그래밍 언어는 Base64 인코딩 및 디코딩을 위한 내장 함수나 표준 라이브러리를 제공합니다. 다음은 인기 있는 언어들의 실용적인 예제입니다:

JavaScript / Node.js

// 브라우저 (최신)
const text = "Hello, World!";
const encoded = btoa(text);
console.log(encoded); // SGVsbG8sIFdvcmxkIQ==

const decoded = atob(encoded);
console.log(decoded); // Hello, World!

// Node.js
const buffer = Buffer.from("Hello, World!");
const encoded = buffer.toString('base64');
console.log(encoded); // SGVsbG8sIFdvcmxkIQ==

const decoded = Buffer.from(encoded, 'base64').toString();
console.log(decoded); // Hello, World!

Python

import base64

# 인코딩
text = "Hello, World!"
encoded = base64.b64encode(text.encode())
print(encoded)  # b'SGVsbG8sIFdvcmxkIQ=='

# 디코딩
decoded = base64.b64decode(encoded).decode()
print(decoded)  # Hello, World!

Java

import java.util.Base64;

// 인코딩
String text = "Hello, World!";
String encoded = Base64.getEncoder().encodeToString(text.getBytes());
System.out.println(encoded); // SGVsbG8sIFdvcmxkIQ==

// 디코딩
byte[] decoded = Base64.getDecoder().decode(encoded);
System.out.println(new String(decoded)); // Hello, World!

명령줄

# 인코딩
echo -n "Hello, World!" | base64
# SGVsbG8sIFdvcmxkIQ==

# 디코딩
echo "SGVsbG8sIFdvcmxkIQ==" | base64 -d
# Hello, World!

# 파일 인코딩
base64 image.png > image.txt

# 파일 디코딩
base64 -d image.txt > image.png

빠른 인코딩 및 디코딩 작업을 위해 코드 작성 없이 브라우저에서 직접 Base64 인코더 도구를 사용할 수 있습니다.

빠른 팁: 바이너리 파일을 인코딩할 때는 항상 텍스트 표현이 아닌 원시 바이트로 작업하세요. 바이너리를 먼저 텍스트로 변환하면 데이터가 손상됩니다.

Base64의 일반적인 사용 사례

Base64 인코딩은 데이터 전송 및 저장에서 특정 문제를 해결합니다. 다음은 Base64를 접하거나 사용해야 하는 가장 일반적인 시나리오입니다:

1. 임베디드 이미지를 위한 데이터 URI

데이터 URI를 사용하면 별도의 HTTP 요청 없이 HTML 또는 CSS에 이미지를 직접 임베드할 수 있습니다. 이는 작은 아이콘, 로고 또는 인라인 SVG에 특히 유용합니다.

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA..." alt="빨간 점" />

/* CSS */
.icon {
  background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0i...);
}

장점으로는 HTTP 요청 감소와 보장된 가용성(깨진 이미지 링크 없음)이 있습니다. 그러나 이는 HTML/CSS 파일 크기를 증가시키고 이미지의 별도 브라우저 캐싱을 방지합니다.

2. 이메일 첨부파일 (MIME)

이메일 프로토콜은 7비트 ASCII 텍스트용으로 설계되었습니다. Base64 인코딩을 사용하면 PDF, 이미지, 문서와 같은 바이너리 첨부파일을 이메일 시스템을 통해 안전하게 전송할 수 있습니다.

MIME(Multipurpose Internet Mail Extensions) 표준은 Base64를 사용하여 이메일 메시지의 첨부파일을 인코딩합니다. 이는 이메일 클라이언트와 서버에 의해 자동으로 처리됩니다.

3. API 인증

HTTP Basic Authentication은 Authorization 헤더에서 자격 증명을 Base64로 인코딩합니다:

// 사용자명: user, 비밀번호: pass
// 결합: user:pass
// Base64: dXNlcjpwYXNz

Authorization: Basic dXNlcjpwYXNz

기억하세요: Base64는 암호화가 아닙니다. HTTP를 통한 Basic Auth는 안전하지 않습니다. 자격 증명을 전송할 때는 항상 HTTPS를 사용하세요.

4. JSON Web Token (JWT)

JWT는 헤더 및 페이로드 섹션에 Base64URL 인코딩(URL 안전 변형)을 사용합니다:

// JWT 구조: header.payload.signature
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

각 섹션은 Base64URL로 인코딩된 JSON이며, 이를 통해 JWT를 URL 및 HTTP 헤더에서 읽고 전송할 수 있습니다.

5. 데이터베이스에 바이너리 데이터 저장

일부 데이터베이스나 데이터 형식(JSON 또는 XML 등)은 바이너리 데이터를 잘 처리하지 못합니다. Base64 인코딩을 사용하면 바이너리 데이터를 텍스트로 저장할 수 있습니다:

{
  "user_id": 12345,
  "profile_image": "iVBORw0KGgoAAAANSUhEUgAAAAUA...",
  "document": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8..."
}

이는 바이너리 데이터를 포함해야 하는 NoSQL 데이터베이스, 구성 파일 및 API 응답에서 일반적입니다.

6. 인증서 및 키 파일

PEM(Privacy Enhanced Mail) 형식은 Base64를 사용하여 인증서, 개인 키 및 공개 키를 인코딩합니다:

-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAKL0UG+mRKmzMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
...
-----END CERTIFICATE-----

이를 통해 인증서와 키를 다양한 시스템에서 이식 가능하게 만들고 복사-붙여넣기가 쉬워집니다.

API 및 웹 개발에서의 Base64

웹 API는 다양한 목적으로 Base64를 자주 사용합니다. 이러한 패턴을 이해하면 타사 API와 효과적으로 작업하고 자신만의 API를 설계하는 데 도움이 됩니다.

파일 업로드 API

많은 API가 JSON 페이로드에서 Base64로 인코딩된 문자열로 파일 업로드를 허용합니다:

POST /api/upload
Content-Type: application/json

{
  "filename": "document.pdf",
  "content": "JVBERi0xLjQKJeLjz9MK...",
  "encoding": "base64"
}

이 접근 방식은 작은 파일에는 잘 작동하지만 대용량 업로드에는 비효율적입니다. 1-2MB 이상의 파일의 경우 multipart/form-data 또는 직접 바이너리 업로드 사용을 고려하세요.

웹훅 페이로드

웹훅은 종종 바이너리 콘텐츠가 JSON 직렬화에서 살아남도록 Base64로 인코딩된 데이터를 포함합니다:

{
  "event": "document.signed",
  "document_id": "doc_123",
  "signed_pdf": "JVBERi0xLjQKJeLjz9MK...",
  "timestamp": "2026-03-31T10:30:00Z"
}

GraphQL과 Base64

GraphQL은 일반적으로 커서 기반 페이지네이션 및 복잡한 ID 인코딩에 Base64를 사용합니다:

query {
  users(first: 10, after: "Y3Vyc29yOjEwMA==") {
    edges {
      cursor
      node {
        id  # 종종 Base64로 인코딩됨: "VXNlcjoxMjM="
        name
      }
    }
  }
}

Relay 사양은 Base64를 사용하여 커서 위치와 전역 ID를 인코딩하는 이 패턴을 대중화했습니다.

전문가 팁: API를 설계할 때 표준 Base64 또는 Base64URL 인코딩을 사용하는지 문서화하세요. 차이는 URL 매개변수에 중요하며 미묘한 버그를 일으킬 수 있습니다.

브라우저 API와 Base64

최신 브라우저 API는 Base64와 자주 작동합니다:

// Canvas를 Base64로
const canvas = document.getElementById('myCanvas');
const dataURL = canvas.toDataURL('image/png');
// data:image/png;base64,iVBORw0KGgo...

// File을 Base64로
const file = document.getElementById('fileInput').files[0];
const reader = new FileReader();
reader.onload = (e) => {
  const base64 = e.target.result.split(',')[1];
  console.log(base64);
};
reader.readAsDataURL(file);

// Base64 인증으로 Fetch
fetch('/api/data', {
  headers: {
    'Authorization': 'Basic ' + btoa('username:password')
  }
});

성능 고려사항 및 오버헤드

Base64 인코딩은 성능, 대역폭 및 저장소에 영향을 미치는 트레이드오프를 수반합니다. 이를 이해하면 언제 사용할지에 대해 정보에 입각한 결정을 내리는 데 도움이 됩니다.

크기 오버헤드

Base64는 데이터 크기를 약 33% 증가시킵니다. 계산은 다음과 같습니다:

원본 크기 Base64 크기 오버헤드
10 KB 13.3 KB +3.3 KB
100 KB 133 KB +33 KB
1 MB 1.33 MB +333 KB
10 MB 13.3 MB +3.3 MB
100 MB 133 MB +33 MB

이 오버헤드는 대역폭이 제한된 환경, 모바일 애플리케이션 및 대용량 파일 전송에 중요합니다.

처리 속도

Base64 인코딩 및 디코딩에는 CPU 사이클이 필요합니다. 소량의 데이터의 경우 이는 무시할 수 있습니다. 대용량 파일이나 높은 처리량 시스템의 경우 병목 현상이 될 수 있습니다.

최신 구현은 고도로 최적화되어 있지만 성능이 중요한 경우 여전히 벤치마크를 수행해야 합니다:

// JavaScript 벤치마크 예제
const data = new Uint8Array(1024 * 1024); // 1MB
crypto.getRandomValues(data);

console.time('encode');
const encoded = btoa(String.fromCharCode(...data));
console.timeEnd('encode');

console.time('decode');
const decoded = atob(encoded);
console.timeEnd('decode');

메모리 사용량

Base64 작업은 일반적으로 원본 데이터와 인코딩된 데이터를 동시에 메모리에 보관해야 합니다. 대용량 파일의 경우 인코딩/디코딩 중에 메모리 요구 사항이 두 배가 될 수 있습니다.

대용량 파일의 경우 스트리밍 접근 방식을 고려하세요:

// Node.js 스트리밍 예제
const fs = require('fs');
const { Transform } = require('stream');

fs.createReadStream('large-file.bin')
  .pipe(new Transform({
    transform(chunk, encoding, callback) {
      callback(null, chunk.toString('base64'));
    }
  }))
  .pipe(fs.createWriteStream('large-file.b64'));
We use cookies for analytics. By continuing, you agree to our Privacy Policy.