ファイルアップロードによる攻撃について
ファイルアップロードの際の脆弱性は、Webアプリケーションがユーザーからアップロードされたファイルを適切に検証せずに処理することで、攻撃者が悪意のあるファイルをサーバーにアップロードし、不正な操作を行うことを可能にする脆弱性です。これにより、リモートコード実行、サーバーの完全制御、データ漏洩などの深刻なリスクが発生する可能性があります。
ファイルアップロードに関する典型的な脆弱性には、以下のようなものがあります:
脆弱なコード例:
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$upload_dir = '/var/www/uploads/';
$upload_file = $upload_dir . basename($_FILES['file']['name']);
if (move_uploaded_file($_FILES['file']['tmp_name'], $upload_file)) {
echo "File successfully uploaded.";
} else {
echo "File upload failed.";
}
}
?>
攻撃手法:
shell.php
のような悪意のあるPHPファイルをアップロードし、そのファイルにアクセスすることで、サーバー上で任意のコードを実行できます。
curl -F "file=@shell.php" http://example.com/upload.php
http://example.com/uploads/shell.php
にアクセスすることで、攻撃者はサーバー上で任意のPHPコードを実行できます。脆弱なコード例:
from flask import Flask, request
app = Flask(__name__)
@app.route('/upload', methods=['POST'])
def upload_file():
file = request.files['file']
file.save('/var/www/uploads/' + file.filename)
return 'File successfully uploaded.'
if __name__ == '__main__':
app.run()
攻撃手法:
evil.py
というPythonスクリプトをアップロードし、アップロードされたファイルをサーバーで実行することで、リモートコード実行を試みます。脆弱なコード例:
const express = require('express');
const multer = require('multer');
const upload = multer({ dest: '/var/www/uploads/' });
const app = express();
app.post('/upload', upload.single('file'), (req, res) => {
res.send('File successfully uploaded.');
});
app.listen(3000);
攻撃手法:
脆弱なコード例:
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.stereotype.Controller;
import java.nio.file.Files;
import java.nio.file.Paths;
@Controller
public class FileUploadController {
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) throws Exception {
Files.write(Paths.get("/var/www/uploads/" + file.getOriginalFilename()), file.getBytes());
return "File successfully uploaded.";
}
}
攻撃手法:
webshell.jsp
のような悪意のあるJSPファイルをアップロードし、サーバーに対してリモートコード実行攻撃を試みます。PHPの例:
$allowed_types = array('image/jpeg', 'image/png');
$file_type = mime_content_type($_FILES['file']['tmp_name']);
if (!in_array($file_type, $allowed_types)) {
die("Invalid file type.");
}
Pythonの例(Flask):
allowed_extensions = {'jpg', 'jpeg', 'png'}
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in allowed_extensions
Node.jsの例(Express):
const path = require('path');
const sanitizedFilename = path.basename(req.file.originalname);
Javaの例(Spring):
String savePath = "/safe/uploads/" + file.getOriginalFilename();
Files.write(Paths.get(savePath), file.getBytes());
PHPの例:
if ($_FILES['file']['size'] > 1048576) { // 1MBを超えるファイルを拒否
die("File is too large.");
}
まとめ: ファイルアップロードは非常に便利な機能ですが、適切なセキュリティ対策が施されていないと、深刻な脆弱性を引き起こす可能性があります。ファイルの種類の検証、ファイル名のサニタイズ、適切なディレクトリ設定、サイズ制限の実装などの防止策を適用することで、これらのリスクを軽減することができます。