Skip to content

Instantly share code, notes, and snippets.

@susimsek
Last active September 13, 2023 02:04
Show Gist options
  • Save susimsek/03b6a4d695b864dfe95d1b31959b3e53 to your computer and use it in GitHub Desktop.
Save susimsek/03b6a4d695b864dfe95d1b31959b3e53 to your computer and use it in GitHub Desktop.
Spring Boot File Content Type Validation With Annotation
@ControllerAdvice
public class CustomExceptionControllerAdvice {
@ExceptionHandler(MultipartException.class)
void handleMultipartException(MultipartException ex,HttpServletResponse response) throws IOException {
response.sendError(HttpStatus.BAD_REQUEST.value(),"Please select a file");
}
@ExceptionHandler(ConstraintViolationException.class)
public void handleConstraintViolationException(ConstraintViolationException ex,HttpServletResponse response) throws IOException {
response.sendError(HttpStatus.BAD_REQUEST.value());
}
}
@RestController
@FieldDefaults(level = AccessLevel.PRIVATE,makeFinal=true)
@RequestMapping("/versions/1")
public class FileController {
@PostMapping("/files")
@ResponseStatus(HttpStatus.OK)
public String createFile(@Validated @ValidFile @RequestPart("file") MultipartFile file {
return file.getOriginalFilename()
}
}
public class FileValidator implements ConstraintValidator<ValidFile, MultipartFile> {
@Override
public void initialize(ValidFile constraintAnnotation) {
}
@Override
public boolean isValid(MultipartFile multipartFile, ConstraintValidatorContext context) {
boolean result = true;
String contentType = multipartFile.getContentType();
if (!isSupportedContentType(contentType)) {
result = false;
}
return result;
}
private boolean isSupportedContentType(String contentType) {
return contentType.equals("text/xml")
|| contentType.equals("application/pdf")
|| contentType.equals("image/png")
|| contentType.equals("image/jpg")
|| contentType.equals("image/jpeg");
}
}
@Documented
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {FileValidator.class})
public @interface ValidFile {
String message() default "Only PDF,XML,PNG or JPG images are allowed";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@yildizmy
Copy link

For validation exceptions e.g. ConstraintViolationException, I use another exception handler. You may have a look at validator package in the following repo:

yildizmy/upload-csv-into-mysql-using-apache-commons-csv

@SharkFourSix
Copy link

This can still be bypassed because you're only relying on the headers, which can be spoofed. True content validation can only happen when you inspect the uploaded file (the temporary file) before accepting it and moving it to your destination

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment