[安全]
7 分鐘閱讀
[安全] Base64 安全最佳實踐
在網路應用程式中使用 Base64 編碼的重要安全考慮。
2025年1月
|
security
// BASE64 不是加密
最關鍵的安全誤解是將 Base64 視為加密。Base64 僅僅是編碼 - 它完全可逆,無需任何金鑰或密碼。
任何人都可以立即解碼 Base64 資料。絕不要依賴 Base64 來保護安全或資料。
// ❌ 錯誤:將 Base64 用作「安全」措施
const password = 'secret123';
const encoded = btoa(password); // cGFzc3dvcmQ=
// 任何人都可以立即解碼這個!
// ✅ 正確:適當的密碼雜湊
import bcrypt from 'bcrypt';
const password = 'secret123';
const hashedPassword = await bcrypt.hash(password, 12);
// 這才是真正安全的
// 輸入驗證
總是驗證 Base64 輸入以防止注入攻擊和應用程式錯誤:
適當的驗證防止惡意輸入造成安全問題或應用程式崩潰。
// 驗證 Base64 格式
function isValidBase64(str) {
// 檢查格式:只允許有效的 Base64 字元
const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
if (!base64Regex.test(str)) {
return false;
}
// 檢查長度(必須是 4 的倍數)
if (str.length % 4 !== 0) {
return false;
}
// 測試解碼
try {
atob(str);
return true;
} catch (e) {
return false;
}
}
// 具有驗證的安全解碼
function safeBase64Decode(input, maxLength = 10000) {
if (typeof input !== 'string') {
throw new Error('輸入必須是字串');
}
if (input.length > maxLength) {
throw new Error('輸入過長');
}
if (!isValidBase64(input)) {
throw new Error('無效的 Base64');
}
return atob(input);
}
// XSS 防護
Base64 資料在解碼後可能包含惡意腳本。在顯示解碼內容時總是進行清理:
絕不要信任來自使用者的 Base64 輸入。在 HTML 渲染前總是進行清理。
// ❌ 危險:直接 HTML 注入
function displayDecodedData(base64) {
const decoded = atob(base64);
document.innerHTML = decoded; // XSS 漏洞!
}
// ✅ 安全:清理輸出
function safeDisplayDecodedData(base64) {
const decoded = atob(base64);
// 創建文字節點(不執行 HTML)
const textNode = document.createTextNode(decoded);
container.appendChild(textNode);
// 或跳脫 HTML 實體
const escaped = decoded
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
container.innerHTML = escaped;
}
// 大小限制
Base64 編碼將資料大小增加約 33%。實施大小限制以防止 DoS 攻擊:
不限制的 Base64 輸入可能消耗過多記憶體和處理能力。
- > 設定最大輸入長度限制
- > 在處理過程中監控記憶體使用量
- > 為長操作實施超時
- > 對大型資料集使用串流
- > 在編碼前考慮壓縮
- > 對 Base64 操作進行速率限制
// 安全令牌處理
使用 Base64 處理令牌或敏感 ID 時,遵循安全最佳實踐:
適當的令牌處理防止未授權存取和基於令牌的攻擊。
// 安全令牌創建
function createSecureToken() {
// 使用加密安全的隨機值
const array = new Uint8Array(32);
crypto.getRandomValues(array);
// 轉換為 Base64 並使其 URL 安全
const base64 = btoa(String.fromCharCode(...array))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
return base64;
}
// 安全令牌驗證
function validateToken(token, expectedLength = 43) {
if (typeof token !== 'string') {
return false;
}
// 檢查長度
if (token.length !== expectedLength) {
return false;
}
// 檢查 URL 安全的 Base64 格式
const urlSafeBase64Regex = /^[A-Za-z0-9_-]+$/;
return urlSafeBase64Regex.test(token);
}
// 資料 URI 安全
Base64 資料 URI 可能包含惡意內容。總是驗證和清理資料 URI:
惡意資料 URI 可能執行腳本、載入外部資源或包含不當內容。
// 驗證資料 URI
function validateDataURI(dataUri, allowedTypes = ['image/png', 'image/jpeg']) {
const dataUriRegex = /^data:([a-zA-Z0-9][a-zA-Z0-9\/+]*);base64,(.+)$/;
const match = dataUri.match(dataUriRegex);
if (!match) {
throw new Error('無效的資料 URI 格式');
}
const [, mimeType, base64Data] = match;
// 驗證 MIME 類型
if (!allowedTypes.includes(mimeType)) {
throw new Error(`不支援的 MIME 類型:${mimeType}`);
}
// 驗證 Base64 資料
if (!isValidBase64(base64Data)) {
throw new Error('資料 URI 中的 Base64 無效');
}
// 檢查大小
const sizeEstimate = (base64Data.length * 3) / 4;
if (sizeEstimate > 1024 * 1024) { // 1MB 限制
throw new Error('資料 URI 過大');
}
return { mimeType, base64Data };
}
// 安全實施檢查清單
- > 絕不將 Base64 用作加密或安全措施
- > 總是驗證 Base64 輸入格式和長度
- > 在顯示前清理解碼的輸出
- > 實施大小限制和超時
- > 對網路應用程式使用 URL 安全的 Base64
- > 驗證資料 URI 的 MIME 類型
- > 對令牌使用加密安全的隨機值
- > 實施適當的錯誤處理
- > 監控潛在的 DoS 攻擊
- > 定期對 Base64 處理程式碼進行安全審計