# python-magic: “확장자 대신 파일 내용을 믿는” 가장 실용적인 방법 서버에 이미지 업로드 기능이 붙으면, 언젠가 이런 요구가 생깁니다. * “`.png`라고 올라오는데… 진짜 PNG 맞아?” * “이 파일이 이미지인지 문서인지 먼저 분기해야 해.” * “외부 파서(Pillow/OpenCV)를 쓰기 전에, 최소한 타입을 확인하고 싶어.” 이때 가장 단단한 출발점은 **확장자**가 아니라 **파일 내용**입니다. 그리고 그 “내용 기반 판별”을 가장 손쉽게 가져오는 도구가 `python-magic`입니다. --- ## python-magic은 무엇을 해주는가 {#sec-a08d76193220} `python-magic`은 **libmagic**이라는 C 라이브러리를 파이썬에서 쓰게 해주는 래퍼입니다. libmagic은 파일의 **헤더(처음 몇 바이트)** 같은 특징을 검사해 파일 타입을 식별합니다. 이 기능은 유닉스의 `file` 명령으로도 제공됩니다. 정리하면: * `file`(리눅스 명령) = “터미널에서 쓰는 인터페이스” * `libmagic` = “핵심 엔진(판별 로직)” * `python-magic` = “파이썬에서 libmagic을 호출하는 얇은 래퍼” 이번 글은 `python-magic`을 중심으로, “이 엔진이 대체 어떻게 파일 타입을 알아맞히는지”를 구조적으로 설명합니다. --- ## 핵심 엔진(libmagic)은 어떻게 동작하는가 {#sec-3ca38aa1c6cf} ![libmagic 라이브러리 작동원리 다이어그램](/media/editor_temp/6/0d5baf67-d72a-4f8d-9f1b-e273eaaba587.png) libmagic의 정체는 간단합니다. > “파일 타입 판별 규칙이 모여 있는 **데이터베이스**를 읽고, > 그 규칙대로 파일 바이트를 검사해서, 가장 그럴듯한 결론을 뽑는다.” 여기서 데이터베이스가 바로 **magic database**(매직 패턴 DB)이고, `file`/libmagic이 함께 씁니다. 보통 시스템에 컴파일된 형태(`magic.mgc`)로 설치돼 있습니다. ### 1) “매직 파일”은 규칙들의 모음이다 {#sec-0d6d47a4ad53} 이 규칙은 기본적으로 이런 구성 요소로 이뤄집니다. * **어디를 볼지**(offset: 파일의 몇 바이트 위치) * **어떤 방식으로 읽을지**(type: 바이트/문자열/정수 등) * **무엇과 비교할지**(expected value/pattern) * **무슨 결론을 낼지**(message/MIME 등) 매뉴얼도 `file`이 “magic patterns”를 검사한다고 설명합니다. 또, 이 규칙들은 한 줄 한 줄이 테스트가 되고(오프셋/타입/값/메시지), 조건이 맞으면 더 구체적인 하위 테스트로 내려가는 “계층 구조”로도 조직됩니다. 리눅스의 `file`명령어에 대해서 자세히 알고 싶으신 분은 아래의 링크를 클릭해보세요. [리눅스 file 명령어 알아보기](https://cmdbox.mikihands.com/file/) ### 2) 규칙 DB는 “텍스트 원본”과 “컴파일된 결과”가 있다 {#sec-3692748a59f7} 매직 DB는 원래 사람이 읽는 텍스트 조각들의 집합일 수 있고, 성능을 위해 보통 컴파일된 바이너리 DB(`.mgc`)로도 제공됩니다. ### 3) 결국 하는 일은 “확장자 대신 파일 내용을 본다” {#sec-9d312e1d9ed0} `file`이 확장자 대신 내용을 보는 타입 추정기라는 점은 오래된 철학입니다. python-magic은 그 철학을 “파이썬 코드 한 줄”로 가져오는 도구라고 보면 됩니다. --- ## python-magic을 어떻게 쓰나 {#sec-d0f1c4230032} 대표적인 사용 패턴은 두 가지입니다. ### 1) MIME 타입으로 받기 (가장 실용적) {#sec-ffe8c3253960} 업로드 처리, 라우팅, 로그/메트릭에 유용합니다. ```python import magic mime = magic.from_file("upload.bin", mime=True) print(mime) # 예: image/png ``` `python-magic`은 libmagic 기반으로 파일 타입 식별을 제공하고, 이 기능은 `file` 명령과 같은 계열이라는 점이 공식 설명에도 그대로 나옵니다. ### 2) bytes로 바로 판별하기 (업로드 스트림에 유리) {#sec-030160959863} 디스크에 저장하기 전에, 업로드된 바이트 일부만 보고 빠르게 판별하고 싶을 때가 많습니다. ```python import magic with open("upload.bin", "rb") as f: head = f.read(4096) mime = magic.from_buffer(head, mime=True) print(mime) ``` (버퍼 기반 판별은 “파일 저장 전 1차 필터”로 특히 좋습니다.) --- ## 개발자 관점에서 어디에 유용한가 {#sec-78dbbfda0e18} ### 1) 업로드 검증의 1차 방어선 {#sec-ea23ba6ff650} * 확장자만으로 분기하지 않기 * “이미지로 처리해도 되는 파일인지” 최소한의 확인하기 ### 2) 처리 파이프라인의 분기점 {#sec-ef95b692a826} * 이미지라면 리사이즈/썸네일 파이프라인으로 * PDF/ZIP이면 다른 워커로 * 미확인 타입이면 격리/거절/추가 검증으로 ### 3) “무거운 디코더”를 호출하기 전에 비용을 줄이기 {#sec-508e3c95c8ee} Pillow 같은 디코더는 강력하지만, 호출 자체가 비용(메모리/CPU/취약점 표면)을 늘립니다. python-magic은 그 전에 “이 작업을 해도 되는지”를 판단하는 데 쓰기 좋습니다. > 중요한 현실 체크: libmagic은 어디까지나 **추정/식별** 도구입니다. > 보안적으로 완전한 판별(악성 페이로드 차단 등)이 목적이라면, 추가 검증(화이트리스트, 크기 제한, 샌드박스 디코딩 등)이 필요합니다. --- ## 마무리: python-magic은 “파일 타입 판별을 코드로 가져오는 가장 가벼운 방법”이다 {#sec-3b1611aa0fb2} python-magic이 제공하는 건 이미지 처리 자체가 아닙니다. 대신 “이 파일을 무엇으로 취급해야 하는지”를 빠르게 알려줍니다. * 엔진은 `file`과 같은 libmagic * 판별 방식은 “규칙 DB + 바이트 검사” * 개발 현장에서는 업로드 검증, 라우팅, 비용 절감에 특히 유용 이걸 익혀두면, 라이브러리가 부족한 환경에서도 “판별 → 분기 → 안전장치”를 구성할 수 있습니다. --- ## 다음 글 예고 {#sec-832d5436b8b1} * Pillow(PIL)의 `open()`, `load()`, `verify()`가 각각 무엇을 보장하고, 언제 어떤 메서드를 써야 하는지, 어떻게 작동하는지를 정리해보겠습니다. --- **관련글 보기** - [개발자가 바라보는 이미지 파일의 모습은? 이미지파일을 분해 해보자](/ko/whitedec/2026/1/14/developer-view-image-file-common-structure/)