[Base64.sh]

zh-Hant v

[安全] 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, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#x27;');
    
    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 處理程式碼進行安全審計