Base64 là gì? Tìm hiểu chi tiết về kỹ thuật mã hóa dành cho lập trình viên

05 tháng 4, 2026·10 phút đọc

Base64 là phương pháp chuyển đổi dữ liệu nhị phân sang dạng văn bản để truyền tải an toàn trên các hệ thống chỉ hỗ trợ chuỗi ký tự như JSON hay Email. Bài viết sẽ giải thích cơ chế hoạt động chi tiết, các trường hợp sử dụng thực tế và các lưu ý quan trọng về hiệu suất cũng như bảo mật.

Base64 là gì? Tìm hiểu chi tiết về kỹ thuật mã hóa dành cho lập trình viên

Base64 là gì? Tìm hiểu chi tiết về kỹ thuật mã hóa dành cho lập trình viên

Mỗi lập trình viên chắc chắn từng nhìn thấy những chuỗi ký tự ngẫu nhiên dài ngoằng — ví dụ như SGVsbG8gV29ybGQ= — và tự hỏi chúng thực sự là gì. Đó chính là Base64 encoding (mã hóa Base64). Một khi bạn hiểu rõ nó, bạn sẽ nhận ra sự xuất hiện của nó ở khắp mọi nơi: trong các JWT token, tệp đính kèm email, bảng样式 CSS, payload của API và nhiều hơn nữa.

Hãy cùng giải mã nó một cách triệt để — không chỉ là "cái gì", mà còn là "như thế nào" và "tại sao".

Base64 thực sự là gì?

Base64 là một cách để biểu diễn dữ liệu nhị phân (binary data) dưới dạng văn bản thuần.

Máy tính lưu trữ mọi thứ dưới dạng nhị phân — hình ảnh, PDF, tệp âm thanh, tệp thực thi — tất cả đều là chuỗi các số 0 và 1. Vấn đề là nhiều hệ thống (HTTP headers, JSON, email, XML) được thiết kế để chỉ xử lý văn bản. Nếu bạn cố gắng đẩy dữ liệu nhị phân thô qua một hệ thống dựa trên văn bản, dữ liệu đó sẽ bị hỏng. Các ký tự bị hiểu sai, byte null bị loại bỏ, ký tự xuống dòng bị lỗi.

Base64 giải quyết vấn đề này bằng cách chuyển đổi dữ liệu nhị phân thành một bộ 64 ký tự ASCII an toàn, có thể in được:

A-Z  (26 ký tự)
a-z  (26 ký tự)
0-9  (10 ký tự)
+, / ( 2 ký tự)
─────────────────────
     64 tổng cộng

Đó chính là nguồn gốc của cái tên — nó sử dụng chính xác 64 ký tự.

Quá trình chuyển đổi diễn ra như thế nào?

Đây là phần mà hầu hết các bài viết thường bỏ qua. Hãy đi sâu vào chi tiết.

Bước 1 — Mọi thứ đều bắt đầu từ nhị phân

Hãy lấy từ "Man" làm ví dụ. Trong mã ASCII:

M = 77  = 01001101
a = 97  = 01100001
n = 110 = 01101110

Ghép chúng lại thành một luồng bit:

01001101 01100001 01101110

Bước 2 — Chia thành các nhóm 6-bit

Byte thông thường là 8 bit. Base64 hoạt động theo đoạn 6-bit vì 2⁶ = 64 (chính xác bằng kích thước bộ ký tự của chúng ta):

010011  010110  000101  101110
  19      22      5       46

Bước 3 — Ánh xạ mỗi giá trị 6-bit thành một ký tự

Base64 có một bảng tra cứu (gọi là bảng chữ cái Base64):

0  = A       16 = Q       32 = g       48 = w
1  = B       17 = R       33 = h       49 = x
2  = C       18 = S       34 = i       50 = y
...
19 = T       22 = W        5 = F       46 = u

Vì vậy, các giá trị 19, 22, 5, 46 của chúng ta sẽ tương ứng với:

19 → T
22 → W
 5 → F
46 → u

"Man" → TWFu

Bạn có thể tự kiểm tra điều này bằng JavaScript:

btoa("Man") // "TWFu"

Vậy ký tự đệm = là để làm gì?

Base64 hoạt động theo nhóm 3 byte (24 bit → bốn đoạn 6-bit). Nếu dữ liệu đầu vào không chia hết cho 3, nó sẽ thêm phần đệm bằng =:

btoa("M")   // "TQ=="  (1 byte → cần 2 ký tự đệm)
btoa("Ma")  // "TWE="  (2 byte → cần 1 ký tự đệm)
btoa("Man") // "TWFu"  (3 byte → không cần đệm)

Các ký tự = chỉ là phần điền thêm — chúng báo cho bộ giải mã biết có bao nhiêu byte thực sự trong nhóm cuối cùng.

Sự đánh đổi về kích thước

Base64 không miễn phí. Quá trình mã hóa sẽ làm tăng kích thước tệp khoảng 33%.

Tại sao? Vì bạn đang biểu diễn 3 byte dữ liệu bằng cách sử dụng 4 ký tự:

Gốc:       3 bytes  = 24 bits
Đã mã hóa: 4 chars  = 4 × 6 bits = 24 bits dữ liệu
           nhưng mỗi ký tự được lưu dưới dạng ASCII 8-bit
           do đó: 4 × 8 = 32 bits trên đĩa
Overhead:  32 - 24 = 8 bits thêm cho mỗi 3 bytes ≈ lớn hơn 33%

Đối với một hình ảnh 100KB, phiên bản Base64 sẽ là khoảng 133KB. Hãy lưu ý điều này khi nhúng các tệp lớn.

Các trường hợp sử dụng thực tế với mã code

1. Nhúng hình ảnh trong HTML/CSS

Thay vì phải thực hiện một yêu cầu HTTP cho tệp ảnh, bạn có thể nhúng nó trực tiếp:

<!-- Ảnh bình thường — cần yêu cầu HTTP -->
<img src="/logo.png" alt="Logo" />

<!-- Ảnh nhúng Base64 — không cần yêu cầu HTTP -->
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." alt="Logo" />

Tương tự trong CSS:

/* Cần yêu cầu HTTP */
.icon {
  background-image: url('/icon.png');
}

/* Tự chứa, không cần yêu cầu */
.icon {
  background-image: url('data:image/png;base64,iVBORw0KGgo...');
}

Điều này hữu ích cho các biểu tượng nhỏ, logo và SVG nội tuyến, nơi việc loại bỏ một vòng lặp HTTP quan trọng hơn kích thước tệp.

2. Gửi tệp qua API

Hầu hết các REST API giao tiếp bằng JSON, vốn chỉ hỗ trợ văn bản. Để gửi một tệp:

// Đọc tệp và chuyển đổi sang Base64
const fileToBase64 = (file) =>
  new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result.split(',')[1]);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });

// Gửi trong JSON payload
const file = document.querySelector('input[type="file"]').files[0];
const base64 = await fileToBase64(file);

await fetch('/api/upload', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    filename: file.name,
    content: base64,
  }),
});

Trên máy chủ (Node.js), giải mã nó ngược lại:

const buffer = Buffer.from(base64String, 'base64');
fs.writeFileSync('output.png', buffer);

3. Token JWT

Nếu bạn đã từng sử dụng xác thực, bạn đã dùng Base64. Một JWT trông như thế này:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4ifQ
.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Mỗi phần được ngăn cách bằng . là mã hóa Base64URL (một biến thể thay thế + bằng -/ bằng _ để an toàn cho URL). Bạn có thể giải mã payload ngay trong trình duyệt:

const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4ifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";

const payload = token.split('.')[1];

// Base64URL → Base64
const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');

console.log(JSON.parse(atob(base64)));
// { sub: "1234567890", name: "John" }

Lưu ý: JWT được mã hóa, không được mã khóa (encrypted). Bất kỳ ai cũng có thể giải mã payload. Tuyệt đối không đưa dữ liệu nhạy cảm vào payload JWT trừ khi nó cũng được mã khóa.

4. Tệp đính kèm Email (MIME)

Đây là lý do Base64 được phát minh. Khi bạn gửi email có tệp đính kèm, ứng dụng email của bạn sẽ mã hóa tệp thành Base64 và bọc nó trong định dạng MIME:

Content-Type: application/pdf; name="invoice.pdf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="invoice.pdf"

JVBERi0xLjQKJeLjz9MKNiAwIG9iago8PAovVHlwZSAvUGFnZQovUGFy
ZW50IDMgMCBSCi9SZXNvdXJjZXMgPDwKL0ZvbnQgPDwKL0YxIDcgMCBS
...

Máy chủ email chỉ nhìn thấy văn bản thuần — không có nhị phân thô — nên không có gì bị hỏng trong quá trình truyền.

Base64 trong trình duyệt — btoaatob

JavaScript có hai hàm tích hợp sẵn:

// Mã hóa: Binary To Ascii
btoa("Hello World")     // "SGVsbG8gV29ybGQ="

// Giải mã: Ascii To Binary
atob("SGVsbG8gV29ybGQ=") // "Hello World"

Tên gọi có thể gây nhầm lẫn — btoa mã hóa sang Base64, atob giải mã từ Base64. Chỉ cần nhớ: binary to ascii = btoa.

Lưu ý quan trọng: btoa sẽ bị lỗi với các ký tự không phải Latinh:

btoa("Hello 🌍") // ❌ InvalidCharacterError

Đối với chuỗi Unicode, hãy sử dụng TextEncoder:

function encodeUnicode(str) {
  const bytes = new TextEncoder().encode(str);
  return btoa(String.fromCharCode(...bytes));
}

function decodeUnicode(str) {
  const bytes = Uint8Array.from(atob(str), c => c.charCodeAt(0));
  return new TextDecoder().decode(bytes);
}

encodeUnicode("Hello 🌍") // hoạt động ✅

Vấn đề quyền riêng tư ít người đề cập

Đây là điều mà hầu hết các bài viết về Base64 hoàn toàn bỏ qua.

Vì Base64 trông giống như một đoạn văn bản hỗn độn, người ta thường lầm tưởng nó an toàn. Nhưng hoàn toàn không phải vậy. Đó là mã hóa (encoding), không phải mã khóa (encryption). Bất kỳ ai cũng có thể giải mã nó trong vài giây:

atob("SGVsbG8sIHRoaXMgaXMgbm90IGEgc2VjcmV0")
// "Hello, this is not a secret"

Nhưng còn một mối lo ngại về quyền riêng tư sâu xa hơn — công cụ bạn sử dụng để mã hóa/giải mã.

Hầu hết các công cụ Base64 trực tuyến hoạt động như sau:

Bạn chọn tệp
    ↓
Tệp được tải lên máy chủ của họ
    ↓
Máy chủ mã hóa/giải mã nó
    ↓
Kết quả được gửi lại cho bạn
    ↓
Tệp của bạn giờ đã sống trên máy chủ của người khác

Với một chuỗi văn bản, điều này có thể không quan trọng. Nhưng còn với:

  • Một tài liệu PDF bảo mật?
  • Một hình ảnh chứa thông tin cá nhân?
  • Một tệp chứa khóa API hoặc thông tin đăng nhập?

Bạn không biết điều gì sẽ xảy ra với dữ liệu của mình khi nó chạm đến máy chủ đó. Nó có thể được ghi log, lưu trữ, phân tích hoặc bị lộ.

Cách xử lý đúng đắn là hoàn toàn dựa trên trình duyệt. Web File API và JavaScript đủ mạnh để mã hóa và giải mã mọi tệp cục bộ — không cần máy chủ:

// Điều này chạy hoàn toàn trong TRÌNH DUYỆT của BẠN
// Không có gì rời khỏi thiết bị của bạn
const reader = new FileReader();
reader.onload = (e) => {
  const base64 = e.target.result.split(',')[1];
  console.log(base64); // đã mã hóa, cục bộ
};
reader.readAsDataURL(file);

Base64 so với Base64URL

Một sự khác biệt nhỏ đáng biết:

                Base64          Base64URL
Ký tự:          A-Z a-z 0-9    A-Z a-z 0-9
                + /             - _
Đệm:           =               Tùy chọn
An toàn trong URL:   Không              Có
Sử dụng trong:       Tệp, emails       JWTs, OAuth,
                     CSS               Tham số URL
// Mã hóa Base64URL
const base64url = btoa(str)
  .replace(/\+/g, '-')
  .replace(/\//g, '_')
  .replace(/=/g, '');

// Giải mã Base64URL
const base64 = base64url
  .replace(/-/g, '+')
  .replace(/_/g, '/');
const decoded = atob(base64);

Tóm tắt nhanh

// Mã hóa chuỗi
btoa("hello")                        // "aGVsbG8="

// Giải mã chuỗi
atob("aGVsbG8=")                     // "hello"

// Mã hóa chuỗi Unicode
const bytes = new TextEncoder().encode("héllo");
btoa(String.fromCharCode(...bytes))  // "aMOpbGxv"

// Mã hóa tệp (trình duyệt)
reader.readAsDataURL(file)            // "data:image/png;base64,..."

// Giải mã thành Blob (trình duyệt)
const bytes = Uint8Array.from(atob(base64), c => c.charCodeAt(0));
const blob = new Blob([bytes], { type: 'image/png' });

// Mã hóa trong Node.js
Buffer.from("hello").toString('base64')         // "aGVsbG8="

// Giải mã trong Node.js
Buffer.from("aGVsbG8=", 'base64').toString()    // "hello"

Lời kết

Base64 là một trong những khái niệm nền tảng xuất hiện liên tục trong phát triển web — API, token xác thực, email, CSS, xử lý tệp. Việc hiểu cách nó hoạt động ở mức bit sẽ khiến nó bớt bí ẩn hơn nhiều.

Các điểm chính cần nhớ:

  • Base64 chuyển đổi nhị phân → 64 ký tự ASCII có thể in được.
  • Nó hoạt động theo khối đầu vào 3 byte → khối đầu ra 4 ký tự.
  • Đầu ra lớn hơn đầu vào khoảng 33%.
  • Đây là mã hóa (encoding), không phải mã khóa (encryption) — tuyệt đối không dùng nó cho mục đích bảo mật.
  • Các công cụ dựa trên trình duyệt luôn an toàn hơn việc tải tệp lên các máy chủ không rõ ràng.
Bài viết được tổng hợp và biên soạn bằng AI từ các nguồn tin tức công nghệ. Nội dung mang tính tham khảo. Xem bài gốc ↗