ファイルアップロード機能では、Content-Typeヘッダーに基づいてファイルの種類を判定することがあります。しかし、このContent-Typeヘッダーはクライアント(攻撃者)が自由に設定可能なため、信頼性が低いです。攻撃者は、このヘッダーを偽装して、意図しないファイル形式をサーバーにアップロードし、任意のスクリプト実行やデータ漏洩を引き起こす可能性があります。
$allowedTypes = ['image/jpeg', 'image/png'];
$fileType = $_FILES['file']['type'];
if (in_array($fileType, $allowedTypes)) {
move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/' . $_FILES['file']['name']);
}
Content-Type: image/jpeg
と偽装してサーバーに送信します。サーバー側では、$_FILES['file']['type']
に依存してチェックを行うため、実際のファイルがPHPスクリプトであっても、画像として扱われてしまいます。たとえば、ファイル名を shell.php
としてアップロードしても、サーバーはその内容を確認せずに保存してしまいます。ALLOWED_TYPES = {'image/jpeg', 'image/png'}
if 'file' in request.files:
file = request.files['file']
if file.content_type in ALLOWED_TYPES:
file.save(os.path.join(app.config['UPLOAD_FOLDER'], file.filename))
Content-Type
を自由に設定できます。たとえば、実際にはスクリプトコードが含まれたファイルに Content-Type: image/png
を指定し、サーバーに画像として認識させることが可能です。const multer = require('multer');
const upload = multer({
fileFilter: function (req, file, cb) {
const allowedTypes = /jpeg|png/;
if (allowedTypes.test(file.mimetype)) {
return cb(null, true);
}
cb('Error: Invalid file type!');
}
});
app.post('/upload', upload.single('file'), (req, res) => {
res.send('File uploaded!');
});
file.mimetype
に偽の値(例えば、image/jpeg
)を設定して送信することでバイパスが可能です。サーバーはContent-Typeヘッダーに依存してチェックを行うため、意図しないファイル形式が受け入れられるリスクがあります。@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file) {
String fileType = file.getContentType();
List<String> allowedTypes = Arrays.asList("image/jpeg", "image/png");
if (allowedTypes.contains(fileType)) {
file.transferTo(new File("uploads/" + file.getOriginalFilename()));
return "File uploaded!";
} else {
return "Invalid file type!";
}
}
Content-Type: image/jpeg
と偽装することで、スクリプトファイルが画像としてアップロードされるケースがあります。サーバーがContent-Typeヘッダーに依存していると、実際のファイル形式にかかわらず処理されてしまいます。Content-Typeヘッダーに依存しない検証 サーバー側でファイルのMIMEタイプや拡張子を検証する際、Content-Typeヘッダーに依存せず、ファイルの内容を検査します。たとえば、画像であれば実際に画像ライブラリを使って解析できるか確認します。
ファイル内容のサーバー側検証 画像ファイルの場合、サーバー側でファイルの内容が正しい形式であるかどうかを検証します。例えば、画像の場合は画像ライブラリを使い、ファイルが正当な画像フォーマットであるかを確認します。
実行可能な場所へのファイル保存を避ける アップロードされたファイルをスクリプトが実行されるディレクトリに保存しないようにします。たとえば、アップロードされたファイルはWeb公開ディレクトリ外に保存し、必要に応じて読み取り専用で提供します。
ファイル名の正規化と安全な保存
ファイル名に予期しない文字列やパターンが含まれないように正規化します。また、secure_filename()
などの方法でファイル名を安全に処理します。
拡張子チェックと同様に、Content-Typeのチェックだけに頼らず、複数の方法でファイルの正当性を検証することが重要です。