Springでファイルアップロードを安全に!サイズ・拡張子・MIMEタイプのバリデーション方法を解説
生徒
「Springのフォームでファイルアップロードさせたいんですが、危ないファイルとかアップされないようにしたいんです。」
先生
「それは大事なポイントですね。ファイルアップロードでは、ファイルサイズ・拡張子・MIMEタイプをきちんとチェックして、不正なファイルを防ぐことが重要です。」
生徒
「それってSpringの機能で簡単にできますか?」
先生
「はい、Springではバリデーションやフォームバインドを使って、しっかりと検証ができますよ。実際にやり方を見ていきましょう。」
1. Springでファイルアップロードを受け取る基本設定
Spring MVCでは、ファイルアップロードの処理にMultipartFileインタフェースを使用します。まずはHTMLフォーム側でファイルを送信できるようにしましょう。
<form method="post" enctype="multipart/form-data" th:action="@{/upload}" th:object="${form}">
<input type="file" th:field="*{file}" class="form-control" />
<button type="submit" class="btn btn-primary mt-2">アップロード</button>
</form>
Spring側では、コントローラーに@ModelAttributeでフォームを受け取り、MultipartFileとしてファイルを扱います。
@Controller
public class FileUploadController {
@PostMapping("/upload")
public String handleUpload(@ModelAttribute FileForm form, Model model) {
MultipartFile file = form.getFile();
// 検証ロジックをここに実装
return "result";
}
}
2. ファイルサイズを検証する方法
セキュリティの基本として、ファイルサイズの上限を設けることは必須です。Springでは設定ファイルで制限する方法と、コードでチェックする方法があります。
まずはapplication.propertiesで最大サイズを指定します。
spring.servlet.multipart.max-file-size=5MB
spring.servlet.multipart.max-request-size=5MB
さらに、プログラム内で細かくチェックするには次のように記述します。
if (file.getSize() > 5 * 1024 * 1024) {
bindingResult.rejectValue("file", "file.tooLarge", "ファイルサイズは5MB以下にしてください");
}
このようにすると、バリデーションエラーを発生させて、ユーザーにメッセージを表示できます。
3. 拡張子のバリデーションチェック
ファイルの拡張子(例:.jpgや.pdf)をチェックすることで、不正なファイル形式のアップロードを防ぎます。
String filename = file.getOriginalFilename();
if (filename != null && !filename.matches(".*\\.(jpg|jpeg|png|pdf)$")) {
bindingResult.rejectValue("file", "file.invalidType", "許可されていないファイル形式です");
}
ただし、拡張子だけでは完全な判定にはなりません。次はMIMEタイプの確認もあわせて行いましょう。
4. MIMEタイプ(コンテンツタイプ)の検証方法
ファイルの中身が本当に画像かPDFかを確認するには、MIMEタイプ(Content-Type)を確認します。
String contentType = file.getContentType();
if (contentType == null ||
!(contentType.equals("image/jpeg") || contentType.equals("image/png") || contentType.equals("application/pdf"))) {
bindingResult.rejectValue("file", "file.invalidMime", "許可されていないMIMEタイプです");
}
このようにすれば、拡張子を偽装したファイルをブロックすることが可能です。セキュリティ対策として重要です。
5. カスタムバリデーターを使って検証をまとめる
毎回コントローラーにバリデーションを書くのは煩雑です。SpringのValidatorインタフェースを使って、検証を共通化しましょう。
@Component
public class FileValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return FileForm.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
FileForm form = (FileForm) target;
MultipartFile file = form.getFile();
if (file == null || file.isEmpty()) {
errors.rejectValue("file", "file.empty", "ファイルが選択されていません");
return;
}
if (file.getSize() > 5 * 1024 * 1024) {
errors.rejectValue("file", "file.tooLarge", "ファイルサイズは5MB以下にしてください");
}
String filename = file.getOriginalFilename();
if (filename != null && !filename.matches(".*\\.(jpg|jpeg|png|pdf)$")) {
errors.rejectValue("file", "file.invalidType", "許可されていないファイル形式です");
}
String contentType = file.getContentType();
if (contentType == null ||
!(contentType.equals("image/jpeg") || contentType.equals("image/png") || contentType.equals("application/pdf"))) {
errors.rejectValue("file", "file.invalidMime", "許可されていないMIMEタイプです");
}
}
}
このようにすることで、コントローラー側はスッキリしたコードになります。
6. コントローラーでValidatorを使用する
バリデーターをコントローラーで使うには、次のように@InitBinderで登録します。
@Controller
public class FileUploadController {
@Autowired
private FileValidator fileValidator;
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(fileValidator);
}
@PostMapping("/upload")
public String upload(@ModelAttribute("form") @Validated FileForm form, BindingResult result) {
if (result.hasErrors()) {
return "form";
}
// 正常なファイル処理
return "success";
}
}
このように@ValidatedとBindingResultを併用することで、ファイルアップロードのバリデーション処理を自動化できます。
7. よくあるエラーとデバッグポイント
ファイルバリデーションでよくある失敗例や見落としポイントも押さえておきましょう。
- ファイルサイズ制限が効かない ⇒
application.propertiesで指定したか確認 - MIMEタイプが常に
application/octet-streamになる ⇒ ブラウザやアップロード手段に依存 - 拡張子チェックが甘い ⇒
.exeなど明示的に除外が必要
検証ロジックは常に攻撃を想定して実装することが、安全なアプリケーションには欠かせません。
Spring FrameworkやThymeleafを使った Webアプリ開発の全体像をやさしく理解したい人には、 この入門書が定番です。
Spring Framework超入門をAmazonで見る※ Amazon広告リンク