[Base64.sh]

zh-Hans v

[安全] 7分钟阅读

[安全] Base64安全最佳实践

在Web应用程序中使用Base64编码时的重要安全考虑。

2025年1月 | security

// BASE64不是加密

最关键的安全误解是将Base64视为加密。Base64只是编码 - 它完全可逆,无需任何密钥或密码。

任何人都可以立即解码Base64数据。永远不要依赖Base64来保证安全性或数据保护。

// ❌ 错误:将Base64用作'安全措施'
const password = '密码123';
const encoded = btoa(password); // 5a+G56CBMTIz
// 任何人都可以立即解码这个!

// ✅ 正确:适当的密码哈希
import bcrypt from 'bcrypt';
const password = '密码123';
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输入格式和长度
  • > 在显示前清理解码输出
  • > 实施大小限制和超时
  • > 为Web应用程序使用URL安全的Base64
  • > 验证数据URI的MIME类型
  • > 为令牌使用加密安全的随机值
  • > 实施适当的错误处理
  • > 监控潜在的DoS攻击
  • > 定期对Base64处理代码进行安全审计