MIME 스니핑과 X-Content-Type-Options: nosniff 설명
브라우저는 서버가 잘못된 Content-Type을 보내더라도 응답의 실제 콘텐츠를 '스니핑'하여 처리 방법을 결정할 수 있습니다. X-Content-Type-Options: nosniff 헤더는 선언된 타입을 신뢰하고 업로드된 이미지 같은 파일을 실행 가능한 스크립트로 승격하는 것을 거부하도록 브라우저에 지시합니다.
무엇인가요
MIME 스니핑은 서버의 Content-Type 헤더가 없거나 콘텐츠와 일치하지 않을 때, 응답의 첫 번째 바이트를 검사하여 콘텐츠 유형을 추론하는 브라우저 휴리스틱입니다. 예를 들어, <script>로 시작하는 text/plain으로 선언된 파일은 HTML로 재분류되어 실행될 수 있습니다.
X-Content-Type-Options는 단일 값 응답 헤더입니다: X-Content-Type-Options: nosniff. 이 헤더가 있으면 브라우저는 응답을 다른 MIME 타입으로 승격하는 것을 거부합니다. application/octet-stream으로 제공되는 업로드 파일은 바이너리 상태를 유지하며 실행 가능한 스크립트나 스타일시트가 되지 않습니다.
왜 중요한가요
사용자 생성 콘텐츠가 주요 위험입니다. 앱에서 파일 업로드를 허용하고 앱과 동일한 오리진에서 제공하는 경우, 이미지로 위장한 악성 HTML 파일이 스니핑될 때 피해자의 브라우저에서 실행될 수 있습니다. 서버 측에서 확장자를 검증하더라도 파일 업로드를 통한 저장형 XSS가 발생할 수 있습니다.
nosniff 없이는 브라우저가 예기치 않은 소스에서 가져온 스타일시트를 실행할 수도 있습니다. 스크립트로 실행되는 스타일시트는 다른 잘못된 구성과 결합하면 크로스 오리진 데이터 유출 경로를 만들어냅니다. nosniff는 앱의 모든 콘텐츠 경계를 강화하는 저비용 글로벌 보호 수단입니다.
고치는 방법
next.config.js에서 X-Content-Type-Options: nosniff를 설정하여 API 라우트와 정적 파일 라우트를 포함한 모든 응답에 적용되도록 합니다.
// next.config.js
module.exports = {
async headers() {
return [
{
source: "/:path*",
headers: [
{ key: "X-Content-Type-Options", value: "nosniff" },
],
},
];
},
};server 블록에 디렉티브를 추가하여 nginx를 통해 프록시되는 모든 응답에 적용되도록 합니다.
add_header X-Content-Type-Options "nosniff" always;nosniff는 각 응답에 정확한 Content-Type 헤더가 있을 때 가장 효과적입니다. 사용자 업로드 파일은 적절한 타입으로 제공하고 앱과 동일한 오리진이 아닌 별도의 오리진이나 스토리지 도메인에서 제공하여, 파일이 실행되더라도 사용자의 세션 쿠키에 접근할 수 없도록 합니다.
확장자 검사는 우회될 수 있습니다. file-type(npm) 같은 라이브러리를 사용하여 서버 측에서 파일의 매직 바이트를 검사하고, 허용된 안전한 타입 목록과 일치하지 않는 것은 스토리지 레이어에 도달하기 전에 거부합니다.
import { fileTypeFromBuffer } from "file-type";
const ALLOWED = new Set(["image/jpeg", "image/png", "image/webp", "image/gif"]);
async function validateUpload(buffer: Buffer): Promise<void> {
const type = await fileTypeFromBuffer(buffer);
if (!type || !ALLOWED.has(type.mime)) {
throw new Error("Upload rejected: unsupported file type");
}
}자주 묻는 질문
AppSafe는 X-Content-Type-Options 헤더 누락을 어떤 심각도로 보고하나요?
중간. 이 헤더는 저마찰 강화 조치(한 줄의 구성)이므로 생략은 명백한 취약점이지만, 실제 악용에는 별도의 업로드 또는 주입 벡터가 필요합니다.
nosniff는 일반적인 페이지 로드에 영향을 주나요?
실제로는 그렇지 않습니다. nosniff는 더 위험한 타입으로의 승격만 차단합니다. HTML, CSS, JavaScript는 이미 올바른 타입으로 제공되므로 정상적으로 로드됩니다.
현대 브라우저가 더 스마트해진 지금도 X-Content-Type-Options가 여전히 관련이 있나요?
네. 스니핑 동작은 엔진과 버전마다 다르며, 이 헤더는 유일한 이식 가능한 보장입니다. 현재 모든 브라우저(Chrome, Firefox, Safari, Edge)는 nosniff를 준수합니다.