[セキュリティ]
7分で読める
[セキュリティ] Base64 セキュリティベストプラクティス
WebアプリケーションでBase64エンコードを使用する際の重要なセキュリティ考慮事項。
2025年1月
|
security
// BASE64は暗号化ではない
最も重要なセキュリティの誤解は、Base64を暗号化として扱うことです。Base64は単なるエンコードであり、キーやパスワードなしで完全に可逆的です。
誰でもBase64データを瞬時にデコードできます。セキュリティやデータ保護にBase64に依存してはいけません。
// ❌ 間違い: Base64を「セキュリティ」として使用
const password = 'secret123';
const encoded = btoa(password); // c2VjcmV0MTIz
// 誰でもこれを瞬時にデコードできます!
// ✅ 正しい: 適切なパスワードハッシュ化
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操作のレート制限
// 安全なトークン処理
トークンや機密IDにBase64を使用する場合、セキュリティのベストプラクティスに従ってください:
適切なトークン処理により、不正アクセスやトークンベースの攻撃を防げます。
// 安全なトークン作成
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処理コードの定期的なセキュリティ監査