우선 MIME 타입이란?
Multipurpose Internet Mail Extensions
SMTP 프로토콜에서 이메일을 보낼때 파일을 확인하기 위해 생성된 표준으로 많은 프로토콜에서 사용됨
이 MIME 타입을 추출하기 위한 대표적인 라이브러리는 Apache의 Tika가 있다.
Apache Tika는 다양한 파일 포맷에서 메타데이터와 텍스트를 추출할 수 있는 강력한 라이브러리이다.
Tika는 두 가지 주요한 모듈로 구성되어 있다.
tika-core는 파일의 기본적인 MIME 타입 체크와 단순 메타데이터 추출 기능을 제공한다. 오직 파일의 내부 구조를 빠르게 확인하기 위한 핵심 기능만 포함하고 있다.
tika-parsers는 tika-core의 기능에 추가하여, 다양한 파일 형식에 맞는 파서를 포함하고 있다. 이를 통해 파일의 내부 콘텐츠를 분석하고 더 세밀한 MIME 타입 판별 및 메타데이터 추출이 가능해진다.
물론 tika-parsers가 내부적으로 더 많은 메타데이터 추출과 분석 작업을 수행해 더 세밀하게 MIME 타입을 확인할 수 있는 대신 처리 속도나 성능 면에서 약간의 오버헤드가 발생할 수 있는데
이 영향은 파일 크기, 처리량, 시스템 환경 등에 따라 달라지므로 정확성이 중요한 경우라면 이 정도 트레이드오프는 감수할 만할 것!
보통 tika에서 밈 타입을 추출하기위해 많이 사용되는 메서드는 다음과 같다.
public String detect(InputStream stream) throws IOException {
return detect(stream, new Metadata());
}
위 메서드는 기본적으로 새 Metadata 객체를 생성하여 내부적으로 detect(InputStream stream, Metadata metadata) 메서드를 호출한다.
public void tikaTest(MultipartFile file) {
Tika tika = new Tika();
try (InputStream is = file.getInputStream()) {
return tika.detect(is);
} catch (IOException e) {
throw new IllegalArgumentException("파일의 MIME 타입 감지 중 오류가 발생했습니다.", e);
}
}
이런 식으로 사용하면 되는데
이 방식은 대부분의 파일에 대해 정상적으로 동작하지만, MS Office 파일들(워드, 엑셀, 파워포인트 등)은 모두 application/x-tika-ooxml으로 인식되는 문제가 있다.
이는 tika-core가 파일 내부의 기본 구조만 확인하기 때문이다.
확장자 위조를 방지하거나 세부 파일 타입(예: docx, xlsx, pptx)을 정확히 구분하기 위해서는 tika-parsers 모듈을 활용해야 한다.
이걸로 충분하다면 상관 없지만 다소 광범위한 MIME 타입으로 나오므로 확장자 위조를 구분하거나, 세부 파일 타입을 확인하기 위해선 tika-parsers의 기능을 사용하는게 좋다.
만약 사용자가 파일 확장자를 조작하더라도, Tika는 파일 시작 부분의 byte magic pattern을 읽어서 MIME 타입을 확인한다.
대부분의 파일은 이 방식으로 실제 파일 형식을 올바르게 판별할 수 있으나, Compound Document
나 Simple Container
와 같이 파일 내부에 여러 content type을 포함할 수 있는 경우에는 단순 magic detection으로는 부정확할 수 있다.
tika에서는 파일 종류를 5가지로 구분한다.
이 중 Compound Document
(xlsx 등)와 Simple Container
(zip 등)는 파일 내부적으로 여러 content type을 가질 수 있으므로, 보다 세밀한 판별을 위해 tika-parsers의 추가적인 파싱 기능이 필요하다.
tika-parsers를 함께 사용하면, 파일 이름 정보를 Metadata 객체에 제공하여 보다 정확한 MIME 타입 판별이 가능하다.
아래와 같이 파일 이름을 메타데이터에 추가하고 detect 메서드에 함께 전달하면, MS Office 파일들이 다음과 같이 세부 MIME 타입으로 인식된다.
application/vnd.openxmlformats-officedocument.wordprocessingml.document
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
application/vnd.openxmlformats-officedocument.presentationml.presentation
사용할 메서드는 오버라이딩 된 detect로
public String detect(InputStream stream, Metadata metadata) throws IOException {
if (stream == null || stream.markSupported()) {
return detector.detect(stream, metadata).toString();
} else {
return detector.detect(new BufferedInputStream(stream), metadata).toString();
}
}
tika-core, tika-parsers 3.1.0 버전 기준으로 사용 예제 코드는 다음과 같다.
public void tikaTest(MultipartFile file) {
Tika tika = new Tika();
Metadata metadata = new Metadata();
// 파일 이름을 설정하여 tika가 파일 확장자 등의 정보를 활용하도록 함
metadata.set(TikaCoreProperties.RESOURCE_NAME_KEY, file.getOriginalFilename());
try (InputStream is = file.getInputStream()) {
// Metadata를 함께 전달하여 정확한 MIME 타입을 감지함
return tika.detect(is);
} catch (IOException e) {
throw new IllegalArgumentException("파일의 MIME 타입 감지 중 오류가 발생했습니다.", e);
}
}
이와 같이 Apache Tika를 활용하면, 파일의 진짜 형식을 보다 정확하게 판별하여 보안과 무결성을 강화할 수 있다. 그러니 프로젝트 요구 사항에 따라 tika-core만 사용할지, tika-parsers 모듈까지 포함할지 결정하면 되겠다.