웹 보안의 기초 체력: 필수 보안 헤더 3종(HSTS, CSP, X-Content-Type) 완벽 가이드
우리가 웹 애플리케이션을 개발하고 배포할 때, 기능 구현만큼이나 중요한 것이 바로 인프라 레벨의 보안입니다. 서버의 코드가 아무리 견고해도 브라우저와 서버 사이의 통신 규약인 HTTP 헤더가 부실하면 예상치 못한 공격에 노출될 수 있어요.
오늘은 현대적인 웹 서비스라면 선택이 아닌 필수인 보안 헤더 3종 세트를 딥다이브 해보겠습니다.
목차
- HTTP Strict-Transport-Security (HSTS)
- X-Content-Type-Options
- Content-Security-Policy (CSP)
- CloudFront에서의 설정 예시
- 자주 묻는 질문 (FAQ)
1. HTTP Strict-Transport-Security (HSTS)
HSTS는 브라우저에게 **“앞으로 이 사이트에 접속할 때는 무조건 HTTPS(암호화 통신)로만 접속해”**라고 강제하는 강력한 지시어입니다.
왜 사용해야 하나요?
사용자가 주소창에 http://를 입력하거나, 해커가 중간에서 통신을 가로채서 보안이 취약한 HTTP로 강제 전환하는 ‘SSL 스트리핑’ 공격을 시도할 수 있습니다. HSTS는 브라우저 단에서 이를 원천 차단하여 암호화되지 않은 구간에서 비밀번호나 세션 쿠키가 탈취되는 위험을 방지합니다.
설정 코드 (Next.js/Node.js 예시)
// next.config.js 또는 커스텀 서버 설정
const securityHeaders = [
{
key: 'Strict-Transport-Security',
// 6개월간 서브도메인을 포함하여 HTTPS 강제
value: 'max-age=15552000; includeSubDomains; preload'
}
];
Tip 💡 >
max-age를 처음부터 길게 잡지 마세요! HTTPS 인증서 설정이 잘못되었을 때 사용자가 아예 접속하지 못하는 상황이 발생할 수 있습니다. 짧은 기간(예: 3600)부터 시작해서 검증 후 점진적으로 늘리는 것이 안전합니다.
2. X-Content-Type-Options
이 헤더는 브라우저의 ‘MIME 스니핑’ 기능을 비활성화하는 역할을 합니다.
방어 목적
브라우저는 가끔 파일의 실제 내용이 선언된 타입(예: .txt)과 다르면 멋대로 해석(예: 스크립트 실행)하곤 해요. 공격자가 일반 이미지나 텍스트 파일인 것처럼 속여서 악성 자바스크립트를 업로드하고 브라우저가 이를 실행하게 만드는 공격을 막기 위해 반드시 nosniff 설정을 해줘야 합니다.
외부 참조 링크
3. Content-Security-Policy (CSP)
가장 강력한 보안 무기인 CSP는 웹 페이지에서 실행할 수 있는 자원(스크립트, 이미지, API 등)의 출처를 화이트리스트로 지정합니다.
XSS 공격의 원천 봉쇄
사이트 게시판이나 댓글창에 악성 스크립트가 심어지더라도, CSP에 명시되지 않은 도메인에서 자원을 가져오거나 실행하는 것을 브라우저가 직접 막아버립니다. “우리 서버 외의 다른 곳에서 온 스크립트는 절대 실행하지 마!”라고 선언하는 식이죠.
실무 설정 예시
// 외부 API 및 분석 도구를 허용하는 CSP 예시
const csp = `
default-src 'self';
script-src 'self' 'unsafe-inline' https://www.google-analytics.com;
connect-src 'self' https://api.my.com https://*.sentry.io;
img-src 'self' data:;
style-src 'self' 'unsafe-inline';
`.replace(/\n/g, "");
CloudFront에서의 설정 예시
우리가 자주 사용하는 AWS CloudFront에서는 Response Headers Policy를 통해 서버 코드 수정 없이도 이 모든 것을 적용할 수 있습니다.
- CloudFront 콘솔 접속
- Policies -> Response headers 선택
- Security headers 탭에서 HSTS, X-Content-Type-Options, CSP를 활성화하고 위에서 다룬 설정값을 입력해요.
자주 묻는 질문 (FAQ)
HSTS 설정을 삭제하고 싶은데 어떻게 하나요?
HSTS는 브라우저에 저장되므로 서버에서 헤더를 지운다고 바로 사라지지 않아요. max-age=0으로 설정된 헤더를 한동안 유지하여 브라우저의 캐시를 무효화해야 합니다.
CSP를 적용하니 외부 폰트나 이미지가 깨져요.
CSP의 화이트리스트에 해당 도메인이 누락되었기 때문입니다. 개발자 도구 콘솔창의 에러 메시지를 확인하여 font-src나 img-src에 필요한 도메인을 추가해 주세요.
no-cache와 no-store는 보안 헤더인가요?
엄밀히는 캐시 제어 헤더이지만, 보안 측면에서 매우 중요합니다. 민감한 개인 정보가 포함된 페이지라면 Cache-Control: no-store를 사용하여 공용 프록시나 브라우저 기록에 남지 않도록 해야 합니다.
보안은 한 번에 완성되는 것이 아니라 지속적으로 관리해야 하는 영역입니다. 오늘 소개한 3종 세트만 제대로 설정해도 여러분의 서비스는 훨씬 견고한 성벽을 갖게 될 거예요!