HTTP 보안 헤더 정리: HSTS·CSP 등 6가지 설정법
HSTS, CSP, X-Frame-Options, Referrer-Policy, Permissions-Policy의 역할과 권장 값, 검토로 표시된 헤더가 항상 취약점은 아닌 이유를 알아보세요.
보안 헤더란
모든 HTTP 응답은 Content-Type: text/html처럼 이름과 값으로 이루어진 헤더로 시작합니다. 그중 몇 가지는 브라우저가 페이지를 다루는 방식을 바꿉니다. 보내는 데 비용이 들지 않고 모든 방문자에게 적용되며, 페이지 HTML이 아니라 서버, 호스팅 플랫폼, 콘텐츠 전송 네트워크(CDN)에서 설정합니다.
IPNixa는 Cloudflare가 모든 페이지와 함께 제공하는 _headers 파일에 자체 헤더를 설정합니다. 이 사이트의 검사기는 입력한 주소를 IPNixa 서버에서 요청하고, 리디렉션을 최대 3번까지 따라간 뒤 최종 응답의 헤더를 읽습니다.
가장 중요한 보안 헤더 6가지
IPNixa 검사기가 판정하는 헤더입니다. 표의 값은 흔히 쓰는 안전한 출발점이므로 사이트에 필요한 대로 조정하세요.
| 헤더 | 막아 주는 것 | 일반적인 값 |
|---|---|---|
| Strict-Transport-Security (HSTS) | 첫 방문 이후 연결이 암호화되지 않은 HTTP로 격하되는 것 | max-age=31536000; includeSubDomains |
| Content-Security-Policy (CSP) | 주입된 스크립트의 실행(교차 사이트 스크립팅 완화) | default-src 'self'; script-src 'self'; frame-ancestors 'none' |
| X-Frame-Options 또는 CSP frame-ancestors | 다른 사이트가 페이지를 숨겨진 프레임에 불러오는 것(클릭재킹) | DENY 또는 frame-ancestors 'none' |
| X-Content-Type-Options | 브라우저가 파일 형식을 추측해 데이터를 스크립트로 실행하는 것 | nosniff |
| Referrer-Policy | 경로와 쿼리 문자열을 포함한 전체 페이지 주소가 다른 사이트로 새는 것 | strict-origin-when-cross-origin |
| Permissions-Policy | 페이지나 삽입된 프레임이 카메라, 마이크, 위치를 사용하는 것 | camera=(), microphone=(), geolocation=() |
IPNixa 검사기의 헤더별 판정 기준
각 헤더는 있음, 검토, 없음 세 가지 상태 중 하나로 표시됩니다. 검토는 헤더는 있지만 값이 아래 기준에 맞지 않는다는 뜻입니다. 보안 점수가 아니라 자세히 살펴보라는 신호입니다.
- HSTS는 헤더가 한 번만 있고 max-age가 15552000초(180일) 이상이면 있음으로 판정합니다. max-age가 더 짧거나 0이면 검토로 표시합니다.
- CSP는 script-src 또는 default-src로 스크립트를 제한하고, 정책 어디에도 'unsafe-inline', 'unsafe-eval', 단독 *가 없으면 있음으로 판정합니다. 보고 전용 정책은 아무것도 차단하지 않으므로 없음으로 표시합니다.
- 프레임 제어는 frame-ancestors 지시문이 'none', 'self' 또는 정확한 주소로 제한되어 있거나, X-Frame-Options가 DENY 또는 SAMEORIGIN이면 있음으로 판정합니다.
- X-Content-Type-Options는 값이 nosniff일 때만 있음으로 판정합니다.
- Referrer-Policy는 마지막 값이 no-referrer, same-origin, strict-origin, strict-origin-when-cross-origin 중 하나이면 있음으로 판정합니다. 브라우저는 이해할 수 있는 마지막 값을 쓰므로 값이 여러 개면 마지막 항목으로 판단합니다.
- Permissions-Policy는 보내기만 하면 있음으로 판정합니다. 어떤 기능을 나열해야 맞는지는 사이트마다 다르기 때문입니다.
실제 사이트가 보내는 헤더: 표본 조사
2026년 11월 2일, 검사기와 같은 사용자 에이전트로 다섯 개 사이트의 홈페이지를 요청하고 응답을 IPNixa 판정 규칙으로 평가했습니다. 헤더는 자주 바뀌므로 특정 시점의 기록으로 보세요.
| 사이트 | HSTS | CSP | 프레임 제어 | nosniff | Referrer | Permissions |
|---|---|---|---|---|---|---|
| github.com | 있음 | 검토 | 있음 | 있음 | 있음 | 없음 |
| ipnixa.com | 있음 | 검토 | 있음 | 있음 | 있음 | 있음 |
| www.wikipedia.org | 있음 | 없음 | 없음 | 없음 | 없음 | 없음 |
| www.google.com | 없음 | 보고 전용 | 있음 | 없음 | 없음 | 없음 |
| example.com | 없음 | 없음 | 없음 | 없음 | 없음 | 없음 |
표본 읽기: 검토가 취약하다는 뜻은 아닙니다
GitHub의 정책은 스크립트를 자체 리소스 호스트와 특정 해시로만 제한하므로 엄격한 편입니다. 검토로 표시된 이유는 style-src가 'unsafe-inline'을 허용하기 때문인데, 판정 규칙은 정책 전체에서 이 키워드를 찾습니다. 인라인 스타일은 인라인 스크립트보다 위험이 훨씬 작으므로, 이는 보안 구멍이라기보다 의도적인 절충입니다.
IPNixa 사이트는 다른 이유로 검토로 표시됩니다. 정책에 frame-ancestors 'none'만 있어 프레임 삽입은 막지만 스크립트는 제한하지 않기 때문입니다. 결과를 있는 그대로 공개합니다.
Google 홈페이지는 스크립트 정책을 Content-Security-Policy-Report-Only로 보내 위반을 차단하지 않고 보고만 하며, 이 응답에는 HSTS도 없었습니다. 대형 사이트는 브라우저 프리로드 목록 같은 다른 방법으로 HTTPS를 강제할 수 있습니다. Wikipedia 포털 페이지는 매우 긴 HSTS max-age를 보내지만 그 밖의 헤더는 거의 없습니다. 이 결과로 각 사이트의 전반적인 보안 수준을 알 수는 없으며, 각 응답이 어떤 브라우저 보호 장치를 요청하는지만 보여 줍니다.
내 사이트에 보안 헤더 추가하기
헤더는 한 번에 하나씩 추가하세요. 추가할 때마다 사이트를 새로고침하고 페이지, 로그인, 삽입된 동영상, 결제 양식이 정상적으로 작동하는지 확인한 뒤 다음 헤더로 넘어갑니다.
- 위험이 적은 헤더부터 시작하세요. X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin, X-Frame-Options: DENY입니다. 단, 다른 사이트가 내 페이지를 프레임에 넣어야 한다면 X-Frame-Options는 제외합니다.
- HSTS는 max-age를 300처럼 짧게 시작하고, 모든 하위 도메인이 HTTPS로 작동하는지 확인한 뒤 31536000으로 늘리세요. includeSubDomains는 모든 하위 도메인이 HTTPS를 지원할 때만 추가합니다.
- Content-Security-Policy를 작성해 먼저 Content-Security-Policy-Report-Only로 보내세요. 위반 보고서를 수집하거나 브라우저 콘솔을 지켜보면서 정상적인 출처는 수정하거나 허용한 다음, 실제로 적용되는 헤더로 전환합니다.
- 사용하지 않는 강력한 기능을 나열한 Permissions-Policy를 추가하세요. 예: camera=(), microphone=(), geolocation=().
- nginx에서는 always 플래그와 함께 add_header를, Apache에서는 Header always set을 사용하세요. 정적 호스팅이나 CDN에서는 플랫폼의 헤더 파일이나 응답 헤더 규칙을 사용합니다.
- IPNixa 헤더 검사를 다시 실행하세요. 빠진 헤더마다 nginx, Apache, _headers 파일에 바로 붙여 넣을 수 있는 줄을 보여 줍니다.
HSTS 프리로드와 기타 주의 사항
HSTS 프리로드 목록은 브라우저에 내장되어 있어 첫 방문부터 HTTPS를 사용하게 합니다. 도메인을 등록하려면 max-age 1년 이상, includeSubDomains, preload 지시문이 필요하며, 목록에서 빠지더라도 사용자에게 반영되기까지 몇 달이 걸립니다. 내부용을 포함한 모든 하위 도메인이 계속 HTTPS를 쓸 수 있을 때만 등록하세요.
X-XSS-Protection은 더 이상 쓰이지 않습니다. 최신 브라우저는 이 헤더를 무시하며 CSP가 그 역할을 대신합니다. 교차 출처 격리 헤더(Cross-Origin-Opener-Policy, Cross-Origin-Embedder-Policy, Cross-Origin-Resource-Policy)는 검사기가 판정하지 않습니다. 공유 메모리 같은 기능을 쓰는 사이트에만 필요하고, 켜면 외부 삽입 콘텐츠가 차단될 수 있기 때문입니다.
자주 묻는 질문
헤더가 없으면 방문하기에 위험한 사이트인가요?
아니요. 보안 헤더는 특정 공격에 대해 브라우저 쪽 보호를 더해 줄 뿐입니다. 헤더가 없어도 잘 관리되는 사이트일 수 있고, 헤더를 모두 갖춰도 다른 결함이 있을 수 있습니다. 결과는 방문자를 위한 판정이 아니라 사이트 운영자를 위한 점검 목록으로 활용하세요.
검사기에 없던 헤더가 내 브라우저에는 보이는 이유는 무엇인가요?
사이트는 페이지, 국가, 로그인 상태, CDN 위치에 따라 다른 헤더를 보낼 수 있습니다. 검사기는 입력한 주소에 대해 Cloudflare 네트워크에서 쿠키 없이 가져온 응답 하나를 읽습니다.
X-Frame-Options와 frame-ancestors 중 무엇을 써야 하나요?
CSP의 frame-ancestors가 최신 방식이며 특정 사이트만 허용할 수도 있습니다. X-Frame-Options도 함께 보내면 오래된 브라우저까지 보호할 수 있습니다. 둘 다 있으면 최신 브라우저는 frame-ancestors를 따릅니다.
로그인이 필요한 페이지도 검사할 수 있나요?
아니요. 검사기는 쿠키나 인증 정보를 보내지 않으며 사설 주소와 로컬 주소는 거부합니다. 로그인이 필요한 페이지나 사설 네트워크의 페이지라면 브라우저 개발자 도구나 curl -I로 원본 응답 헤더를 복사해 검사기에 붙여 넣으세요. 붙여 넣은 헤더는 브라우저 안에서 분석합니다.