파일 업로드를 구현할 때 특정 타입의 파일만 업로드 가능하도록 제한하고 싶은 경우가 있다. 이걸 구현하기 위해 파일 이름에서 확장자를 분리하거나 브라우저로부터 파일을 업로드 할 때 전달되는 MIME 타입을 사용하는 경우가 많다. 하지만 이 방법들은 사용자의 입력을 순순히 받아들인다는 점에서 악용 될 가능성이 존재한다.
보안을 위해서는 사용자에게서 최소한의 정보만 받아들이고 이 정보들도 철저하게 검증해야 한다. 위의 방법들은 무조건적으로 사용자의 입력을 신뢰하고, 브라우저 또한 확장자를 기준으로 MIME 타입을 결정하기에 잘못된 MIME 타입으로 판단할 위험성이 높다. 사용자가 jpg 파일을 png 확장자로 바꿔서 올리고 서버는 그대로 png 파일이라고 제공하는 해프닝부터 시작하여 악성코드를 이미지 확장자로 위장하여 업로드하고 배포 서버로 악용되는 큰 문제까지 발생할 수 있다.
이 문제를 해결하기 위해서는 서버측에서 파일 내용을 기준으로 검증해야 한다. PHP는 파일의 특징적인 데이터를 기준으로 MIME 타입을 판단하는 mime_content_type() 함수를 제공한다. 이 함수를 사용하여 파일의 타입을 확인하고 허용한 타입인지 아닌지 판단하면 된다. mime_content_type() 함수의 인자는 파일 경로의 문자열이다.
아래는 파일이 jpeg, png, svg, mkv, mp4 중 하나인지 확인하는 코드이다:
$allowed_types = ['image/jpeg', 'image/png', 'image/svg+xml', 'video/x-matroska', 'video/mp4']; $mime = mime_content_type($filePath); if($mime === false) throw new Exception('mime_content_type failed'); if(in_array($mime, $allowed_types)) { // allowed } else { // denied }
mime_content_type() 함수가 잘못 판단할 경우를 걱정하는 사람이 있을 수 있다. 하지만 나는 지금까지 그런 경우를 보지 못했고, 예상과 다른 결과가 나온다면 오히려 그 파일이 잘못되었을 가능성이 더 높다.