Build-UP
What
파일 확장자란
파일 형태를 식별할 수 있는 카테고리 이다.
파일 확장자는 보통 이렇게 “xxxx.${확장자}” 표시가 된다.
파일 확장자 구분은 2가지 형태로 식별가능하다.
- 이름
( “xxxx.${확장자}” ) 이처럼 육안으로 식별이 가능하다. 하지만 이러한 구분법은 한편으로는 변경이 쉽다. 그래서 악의적인 파일들을 .png, .jpg 처럼 위장하여 들어와 보안적으로 이슈가 되기도한다.
- 파일 내부 시그니처
파일의 형태마다 16진수로 이루어진 내부에 일정한 규칙이 있다.
abc.jpg 원본 파일이 있다.
실제로 해당 파일의 확장자를 임의로 바꿔보았다.

육안으로 식별가능한 이름은 변경되었지만 내부적인 파일 16진수는 변하지 않는 다는 것을 확인할 수 있다.
이름 기반(텍스트기반) 검증은 위장하면 쉽게 통과할 수 있다.
Why [확장자 검증이 필요한 이유]
악의적인 파일이 서버로 업로드되어 바이러스에 노출되어 심각한 보안 위협을 부를 수 있기 때문이다.
프론트에서도 막을 수 있지만, 서버내에서도 반드시 검증이 필요하다고 생각한다.
How
스프링부트 + 아파치 티카 라이브러리를 이용한 파일 시그니처 검증
build.gradle 추가
implementation group: 'org.apache.tika', name: 'tika-core', version: '1.24'
아파치 티카를 통한 코드 검증
public class FileUtils { public static boolean validImgFile(InputStream inputStream) { Tika tika = new Tika(); // 티카 생성 try { List<String> notValidTypeList = Arrays.asList("image/jpeg", "image/pjpeg", "image/png", "image/gif", "image/bmp", "image/x-windows-bmp"); String mimeType = tika.detect(inputStream); System.out.println("MimeType : " + mimeType); boolean isValid = notValidTypeList.stream().anyMatch(notValidType -> notValidType.equalsIgnoreCase(mimeType)); return isValid; } catch (IOException e) { e.printStackTrace(); return false; } }
주의사항
스프링부트는 멀티스레드 기반이라는 사실을 알아야한다.
그렇기 때문에
private static final Tika tika = new Tika();
전역으로 선언하면 안된다.아파치 티카 검증 매커니즘 살펴보기
- Detector 를 호출하여 파일 시그니처 검증을 시작한다.

2. Detector의 구현체 중 CompositDetector를 사용한다.

3. Detector의 구현체 중 CompositDetector의 detect method 를 호출하여 검증을 시작하고, Header 값을 1024 * 64 만큼 읽어온다.


4. readMagicHeader 를 보면 실제로 byte를 읽어 오게 된다.

5.그에 따른 byte 값을 바탕으로 추정할 수 있는 MimeType을 추출하여 result List<T>에 담아낸다.

6. 실제로 검증 결과를 보면 exe 파일로 둔갑한 파일이 image/png 형식의 MimeType으로 잘 검증되는 것을 볼 수 있다.

아파치 티카 검증 매커니즘을 간단히 요약하면 파일 시그니처를 정확히 판별하기 위해 65536byte까지 읽어온다.
이미지 및 동영상 파일로만 서비스 하는 곳이면 65536 byte까지 읽어와 검증할 필요가 없을 것이다. 이점에서 개선의 여지를 발견했다. 그래서 detect 메커니즘과 유사하게 재구현하였다.
- 서비스할 대상인 파일 확장자 offset을 고정하고

- 실제 verify 메소드 안으로 들어가 multipart Type의 파일 오프셋을 65536 까지 읽어오질 않고 단 4byte만 읽어오도록 하였다.

- 더불어 코드로 반복적으로 호출하는 표현을 줄이기 위해 Validation으로 커스텀하여 사용하기 용이하게 하였다.


REFER
파일 시그니처 모음