인셔셔RSS 관심 있는 블로그, 뉴스, 기술 정보를 효율적으로 추적하고 읽으세요
원문 읽기 InertiaRSS에서 열기

추천 피드

小众软件
小众软件
博客园 - 叶小钗
有赞技术团队
有赞技术团队
大猫的无限游戏
大猫的无限游戏
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
Hugging Face - Blog
Hugging Face - Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
aimingoo的专栏
aimingoo的专栏
Blog — PlanetScale
Blog — PlanetScale
爱范儿
爱范儿
T
Tailwind CSS Blog
Jina AI
Jina AI
量子位
Stack Overflow Blog
Stack Overflow Blog
人人都是产品经理
人人都是产品经理
J
Java Code Geeks
V
Visual Studio Blog
月光博客
月光博客

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python)
Base64 설명 — 이것이 무엇인지, 언제 사용하는지, 그리고 개발자를 괴롭히는 함정들
William Andr · 2026-05-28 · via DEV Community

긴 문자열과 숫자가 ==로 끝나는 것을 보고 그것이 무엇인지 궁금해합니다. JWT를 도구에 붙여넣으면 중간 부분이 대부분 읽을 수 있습니다. HTML 이메일에 이미지를 삽입하면 src 속성이 문자로 가득 차 있습니다. PDF를 API에 업로드하면 문서에 'Base64로 보내십시오'라고 나와 있습니다. 모두 동일한 인코딩이며, 대부분의 개발자는 실제로 무엇을 하는지 제대로 이해하지 못한 채 사용합니다.

이 가이드는 Base64가 실제로 무엇인지, 언제 사용해야 하는지, 일반적인 실수(가장 큰 실수인 암호화로 착각하는 것을 포함), URL 안전 변형, 패딩 규칙, 그리고 모든 주요 언어에서 인코딩 및 디코딩하는 방법을 다룹니다.

Base64가 실제로 무엇인가

Base64는 64개의 특정 문자를 사용하여 이진 데이터를 ASCII 텍스트로 변환하는 인코딩입니다: A-Z, a-z,0-9, +/이(가) 추가됩니다. = 문자는 끝에 패딩하는 데 사용됩니다. 입력의 3바이트마다 정확히 4개의 Base64 문자가 출력되므로, Base64는 데이터 크기를 약 33% 증가시킵니다.

Input bytes:   "Hi"                  (2 bytes: 0x48 0x69)
Binary:        01001000 01101001
Group in 6s:   010010 000110 1001(00)   ← last group padded with zeros
Base64 chars:  S      G      k    =     ← '=' = padding

Result:        "SGk="

전체 화면 모드 전환 전체 화면 모드 종료

수학: 64개의 문자는 각 문자가 6비트를 나타냄을 의미합니다. 6비트(하나의 Base64 문자)와 8비트(1바이트)의 최소공배수는 24비트이며, 이는 3바이트 또는 4개의 Base64 문자에 해당합니다. 이것이 Base64가 항상 4개의 출력 문자 그룹으로 작동하고 패딩이 존재하는 이유입니다.


가장 큰 오해: Base64는 암호화가 아닙니다.

이것은 개발자와 비개발자 모두를 사로잡습니다. Base64는 횡설수설처럼 보이기 때문에 비밀처럼 느껴집니다. 하지만 그렇지 않습니다. 누구나 Base64를 즉시 디코딩할 수 있습니다. 키, 비밀번호, 크랙할 알고리즘도 없습니다. 이는 투명한 변환으로, 다른 알파벳으로 쓰는 것과 같습니다.

// "Encrypted" password?
"cGFzc3dvcmQxMjM="

// Decoded in one line
atob("cGFzc3dvcmQxMjM=")
// → "password123"

전체 화면 모드로 전환 전체 화면 모드 종료

Base64는 인코딩이지 암호화가 아닙니다. 그것을 사용하여 운송하다 데이터를 텍스트 전용 채널을 통해 안전하게 전송 — 숨기다 데이터에 절대 사용하지 마세요. 기밀성이 필요하다면 실제 암호화를 사용하세요: 전송 중인 데이터에 AES, NaCl/libsodium 또는 TLS.


Base64 사용 시기

Base64는 텍스트를 예상하는 시스템을 통해 바이너리 데이터를 이동하기 위해 존재합니다. 가장 일반적인 경우:

JSON 또는 XML에 바이너리 포함 — 어느 형식도 원시 바이트를 지원하지 않습니다. JSON 페이로드의 일부로 파일 업로드를 허용하는 API는 파일을 나타내기 위해 Base64를 사용합니다.

데이터 URL(Data URLs)data:image/png;base64,iVBORw0KGgo...는 별도의 HTTP 요청 없이 이미지를 인라인으로 삽입할 수 있습니다. 작은 아이콘과 이메일 서명에 유용합니다.

HTTP 기본 인증(HTTP Basic Auth)Authorization 헤더는 자격 증명을 다음으로 보냅니다.Basic <base64-of-username:password>. 이것은 Base64가 암호화가 아닌 이유에 대한 완벽한 예이기도 합니다. Basic Auth는 HTTPS와 함께 사용될 때만 안전합니다.

JWT — JSON Web Token은 점으로 구분된 세 개의 Base64URL 인코딩 섹션으로 구성됩니다. 헤더와 페이로드는 읽을 수 있는 JSON이며, 서명만 불투명합니다.

이메일 첨부 파일 — SMTP는 기술적으로 7비트 텍스트 프로토콜이므로 MIME 표준 이후로 첨부 파일은 기본적으로 Base64로 인코딩됩니다.

암호화 키 및 인증서 — PEM 파일(-----BEGIN CERTIFICATE----- 블록)은 Base64로 인코딩된 바이너리 키를 래핑합니다.


패딩 — 일부 Base64가 =로 끝나는 이유와 그렇지 않은 이유

= Base64 문자열의 끝에 있는 것은 패딩입니다. 이는 Base64가 3개의 입력 바이트 단위로 작동하며, 모든 입력이 3바이트의 배수가 아니기 때문입니다. 입력이 1 또는 2바이트 부족할 경우, 인코더는 출력을 = 문자로 패딩하여 결과가 항상 4문자의 배수가 되도록 합니다.

Input length (mod 3)   Padding   Example
─────────────────────────────────────────
0 (multiple of 3)      none      "Man"  → "TWFu"
1                      ==        "M"    → "TQ=="
2                      =         "Ma"   → "TWE="

전체 화면 모드로 전환 전체 화면 모드 종료

일부 인코더와 프로토콜은 바이트를 절약하기 위해 패딩을 제거합니다. JWT가 그렇습니다. JWT 내부의 Base64URL 인코딩에는 패딩이 전혀 없습니다. JWT에서 Base64를 수동으로 디코딩하는 경우 일부 디코더가 이를 받아들이기 전에 패딩을 다시 추가해야 할 수 있습니다.

// JavaScript: add padding back to an unpadded Base64 string
function pad(b64) {
  const remainder = b64.length % 4;
  return remainder ? b64 + '='.repeat(4 - remainder) : b64;
}

전체 화면 모드로 전환 전체 화면 모드 종료


Base64와 Base64URL 비교 — 웹에서 중요한 변형

표준 Base64는 62번째와 63번째 문자로 +/를 사용합니다. 둘 다 URL에서 특별한 의미를 가집니다: +는 쿼리 문자열에서 "공백"을 의미하고, /는 경로 구분자입니다. 표준 Base64를 추가 인코딩 없이 URL에 넣으면 문제가 발생합니다.

Base64URL(RFC 4648에 정의됨)은 이러한 문자를 교체하여 이 문제를 해결합니다: +이(가)-/_이 됩니다. 또한 일반적으로 패딩을 생략합니다. 결과는 URL, 파일 이름 및 HTTP 헤더에 직접 넣어도 안전합니다.

Standard Base64:   "abc/d+ef=="
Base64URL:         "abc_d-ef"

// Convert one to the other
const toUrlSafe = (b64) => b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
const fromUrlSafe = (b64u) => {
  const b64 = b64u.replace(/-/g, '+').replace(/_/g, '/');
  return pad(b64); // add padding back
};

전체 화면 모드로 전환 전체 화면 모드 종료

JWT는 Base64URL을 사용합니다. 대부분의 최신 토큰 형식, OAuth 상태 매개변수 및 URL로 전송되는 다른 모든 것들도 마찬가지입니다.


JavaScript에서의 인코딩 및 디코딩

JavaScript에는 두 개의 내장 함수가 있습니다.btoa()(2진수-ASCII 변환, 인코딩) 및atob()(ASCII-to-binary, decode). 이름들이 혼란스럽습니다 — 임의의 이진 데이터에 대해 예상한 대로 작동하지 않습니다.

// Simple ASCII strings — these work
btoa("Hello, world!");
// → "SGVsbG8sIHdvcmxkIQ=="

atob("SGVsbG8sIHdvcmxkIQ==");
// → "Hello, world!"

// Unicode strings — this BREAKS
btoa("héllo");
// → DOMException: invalid character

// Correct way for Unicode: encode to UTF-8 first
function utf8ToBase64(str) {
  return btoa(unescape(encodeURIComponent(str)));
}
function base64ToUtf8(b64) {
  return decodeURIComponent(escape(atob(b64)));
}

utf8ToBase64("héllo");   // → "aMOpbGxv"
base64ToUtf8("aMOpbGxv"); // → "héllo"

// Modern alternative (Node 16+, modern browsers)
const bytes = new TextEncoder().encode("héllo");
const b64 = btoa(String.fromCharCode(...bytes));

전체 화면 모드로 전환 전체 화면 모드 종료

파일 업로드와 같은 이진 데이터의 경우, 작업하세요.ArrayBuffer또는Uint8Array:":

// Convert a file to Base64 (browser)
async function fileToBase64(file) {
  const buffer = await file.arrayBuffer();
  const bytes = new Uint8Array(buffer);
  let binary = '';
  for (const byte of bytes) binary += String.fromCharCode(byte);
  return btoa(binary);
}

// FileReader alternative — gives you a data URL
function fileToDataUrl(file) {
  return new Promise(resolve => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.readAsDataURL(file);
  });
}

전체 화면 모드로 전환 전체 화면 모드 종료


Python에서 인코딩 및 디코딩

import base64

# Encode a string
encoded = base64.b64encode(b"Hello, world!")
# → b"SGVsbG8sIHdvcmxkIQ=="

# Decode
decoded = base64.b64decode(b"SGVsbG8sIHdvcmxkIQ==")
# → b"Hello, world!"

# URL-safe variant — for JWTs, URLs, filenames
url_safe = base64.urlsafe_b64encode(b"data with /and+chars")
# → b"ZGF0YSB3aXRoIC9hbmQrY2hhcnM="

# Encode a file
with open("photo.jpg", "rb") as f:
    encoded_file = base64.b64encode(f.read()).decode("ascii")

전체 화면 모드로 전환 전체 화면 모드 종료


명령줄에서 인코딩 및 디코딩

# macOS and Linux — encode
echo -n "Hello, world!" | base64
# → SGVsbG8sIHdvcmxkIQ==

# Decode
echo "SGVsbG8sIHdvcmxkIQ==" | base64 -d
# → Hello, world!

# Encode a file
base64 photo.jpg > photo.txt

# Decode a file
base64 -d photo.txt > photo.jpg

# Watch out — many systems wrap output at 76 characters by default
# Use -w 0 (GNU) or no flag (BSD) to disable wrapping
echo -n "long content..." | base64 -w 0

전체 화면 모드로 전환 전체 화면 모드 종료


SQL에서 인코딩 및 디코딩

-- PostgreSQL
SELECT encode('Hello, world!'::bytea, 'base64');
-- → SGVsbG8sIHdvcmxkIQ==

SELECT convert_from(decode('SGVsbG8sIHdvcmxkIQ==', 'base64'), 'UTF8');
-- → Hello, world!

-- MySQL 8+
SELECT TO_BASE64('Hello, world!');
-- → SGVsbG8sIHdvcmxkIQ==

SELECT FROM_BASE64('SGVsbG8sIHdvcmxkIQ==');
-- → Hello, world!

전체 화면 모드로 전환 전체 화면 모드 종료


일반적인 버그와 이를 방지하는 방법

줄 바꿈 함정. 일부 구현체(특히 MIME 및 OpenSSL)는 Base64 출력을 64자 또는 76자마다 줄 바꿈으로 감쌉니다. 다른 구현체는 줄 바꿈이 포함된 입력을 거부합니다. 유효한 Base64처럼 보이는 문자열을 디코딩할 때 "잘못된 문자" 오류가 발생하면 먼저 공백을 제거하십시오.

패딩 불일치. JWT와 URL-safe Base64는 일반적으로 패딩을 생략합니다. 많은 디코더가 패딩을 필요로 합니다. 디코딩이 실패하면, 몇 개의 = 문자를 추가해야 하는지 계산하십시오: (4 - (length % 4)) % 4 그 중에서.

UTF-8 가정. Base64는 바이트를 인코딩하며, 문자를 인코딩하지 않습니다. 문자열을 인코딩하려면 해당 문자열이 어떤 문자 인코딩을 사용하는지 알아야 합니다. 항상 인코딩을 명시적으로 지정하고(UTF-8이 거의 항상 올바른 답입니다), 결과를 문자열로 처리하기 전에 다시 바이트로 디코딩하십시오.

크기의 놀라움. Base64는 페이로드 크기를 33% 증가시킵니다. 작은 자산의 경우 문제되지 않지만, JSON에 포함된 10MB 파일의 경우 와이어를 통해 13.3MB를 전송하게 됩니다. 더 큰 파일의 경우 멀티파트 업로드를 선호하십시오.

이것을 비밀로 취급하십시오. 두 번 말할 가치가 있습니다: Base64는 암호화가 아닙니다. 비밀번호, API 키 또는 기타 민감한 데이터를 Base64로 저장하여 숨겨질 것이라고 기대하지 마세요. 인코딩된 문자열을 볼 수 있다면 원본도 볼 수 있습니다.


저는 DevCrate를 개발한 William입니다. Base64 도구는는 의심스러운 온라인 변환기에 무작위 문자열을 넣어 안에 무엇이 있는지 확인하는 것에 지쳐서 만들어졌습니다. 이것은 표준 및 URL-safe 변형을 인코딩 및 디코딩하고, 파일을 처리하며, 사용자 컴퓨터에서 단 하나의 바이트도 보내지 않습니다.

이 가이드에서 다루지 않은 Base64 사례가 있다면 댓글에 남겨주세요. 모든 댓글을 읽습니다.