업데이트됨 1개월 전
보안 헤더는 자신의 코드를 완전히 신뢰할 수 없기 때문에 존재합니다—그리고 신뢰해서는 안 됩니다.
아무리 주의를 기울여도 애플리케이션에는 취약점이 있을 수 있습니다. 크로스사이트 스크립팅, 클릭재킹, 프로토콜 다운그레이드—이런 공격들은 코드가 이를 막지 못할 때 성공합니다. 보안 헤더는 보안 적용의 주체를 애플리케이션에서 브라우저 자체로 옮깁니다. 코드에 버그가 있더라도 브라우저가 공격 실행을 거부합니다.
바로 이것이 핵심입니다: 보안 헤더는 자신이 실수할 수 있다는 것을 알기 때문에 설치하는 안전장치입니다.
Strict-Transport-Security (HSTS)
공격자가 브라우저를 속여 HTTP를 사용하게 만들 수 있다면 HTTPS는 의미가 없습니다. HSTS는 HTTPS를 필수로 만듭니다.
브라우저가 이 헤더를 한 번 보면, HTTP로 연결하는 것을 거부합니다. 모든 요청이 자동으로 HTTPS가 됩니다. 인증서가 유효하지 않으면 우회 버튼이 없습니다—브라우저는 그냥 연결하지 않습니다.
지시문
max-age는 브라우저가 이 규칙을 기억하는 기간을 설정합니다. 31,536,000초는 1년입니다.
includeSubDomains는 규칙을 모든 서브도메인으로 확장합니다. 이것을 활성화하기 전에 모든 서브도메인이 HTTPS를 지원하는지 반드시 확인하세요—그렇지 않으면 해당 서브도메인에 접근할 수 없게 됩니다.
preload는 hstspreload.org의 브라우저 프리로드 목록에 도메인을 제출할 수 있게 해줍니다. 이 목록의 도메인들은 브라우저에 HTTPS 전용으로 하드코딩됩니다.
첫 방문 문제
HSTS에는 분명한 한계가 하나 있습니다: 첫 번째 방문을 보호할 수 없습니다. 브라우저가 헤더를 받기 전에는 HTTPS를 사용해야 한다는 것을 모릅니다. 첫 번째 연결을 가로채는 공격자는 이를 HTTP로 다운그레이드할 수 있습니다.
프리로드 목록은 바로 이 한계 때문에 생겼습니다. 프리로드 목록에 등록된 도메인은 처음 방문하는 사람도 보호됩니다—규칙이 브라우저 자체에 내장되어 있기 때문입니다.
Content-Security-Policy (CSP)
CSP는 가장 강력한 보안 헤더입니다. 브라우저에 어떤 리소스를 로드하고 실행할 수 있는지 정확히 알려줍니다.
공격자가 악성 스크립트를 페이지에 삽입해도 CSP가 실행을 차단합니다. 허용된 출처와 일치하지 않으면 브라우저가 실행을 거부합니다.
핵심 지시문
default-src는 명시적으로 설정하지 않은 모든 리소스 유형에 적용되는 기본 규칙입니다:
script-src는 JavaScript를 로드할 수 있는 위치를 제어합니다:
style-src는 스타일시트를 제어합니다:
img-src는 이미지를 제어합니다:
connect-src는 fetch, XMLHttpRequest, WebSocket, EventSource를 제어합니다:
frame-ancestors는 누가 프레임 안에 페이지를 삽입할 수 있는지 제어합니다:
출처 값
**'none'**은 모든 것을 차단합니다:
**'self'**는 자신의 출처를 허용합니다:
**'unsafe-inline'**은 인라인 스크립트를 허용합니다—가능하면 피하세요:
**'unsafe-eval'**은 eval()을 허용합니다—이것도 피하세요:
**nonce-[값]**은 일치하는 nonce를 포함하는 특정 인라인 스크립트를 허용합니다:
도메인 출처는 특정 출처를 허용합니다:
엄격하게 시작하기
제한적인 정책으로 시작하세요:
그런 다음 문제가 생기는 것만 완화하세요. 차단 없이 테스트하려면 Report-Only 모드를 사용하세요:
이 모드는 정책을 적용하지 않고 위반 사항을 기록합니다. 배포 전에 정책이 실제로 무엇을 차단할지 미리 파악할 수 있습니다.
X-Content-Type-Options
브라우저는 때때로 파일이 무엇인지 알려줘도 무시하고 스스로 추측합니다. 이미지가 JavaScript로 해석될 수 있고, 텍스트 파일이 HTML로 렌더링될 수 있습니다.
이 단일 지시문은 브라우저에게 말합니다: Content-Type 헤더를 신뢰하고, 추측하지 마세요. 이미지라고 하면 이미지로 처리하고, 코드로 실행하지 마세요.
X-Frame-Options
클릭재킹은 사이트를 보이지 않는 프레임에 삽입한 뒤 악성 페이지 위에 겹쳐서 작동합니다. 사용자는 다른 것을 클릭한다고 생각하지만, 실제로는 숨겨진 사이트와 상호작용하게 됩니다.
DENY는 모든 프레임 삽입을 방지합니다. SAMEORIGIN은 같은 출처에서만 프레임 삽입을 허용합니다.
현대 애플리케이션에서는 CSP의 frame-ancestors를 대신 사용하는 것이 좋습니다:
CSP가 더 유연하며, X-Frame-Options는 사실상 구식이 되었습니다.
Referrer-Policy
링크를 클릭하면 브라우저는 목적지에 어디서 왔는지 알려줍니다. 이 리퍼러 URL에는 민감한 정보—토큰, 세션 ID, 쿼리 문자열에 포함된 개인 데이터—가 담길 수 있습니다.
이 정책은 같은 출처 요청에는 전체 URL을 보내지만, 다른 출처 요청에는 출처만(경로나 쿼리 문자열 제외) 보냅니다. 대부분의 애플리케이션에 적합한 균형입니다.
다른 옵션들:
- no-referrer: 리퍼러 정보를 전혀 보내지 않음
- same-origin: 같은 출처 요청에만 리퍼러를 보냄
- strict-origin: 출처만 보내고, HTTP로 다운그레이드할 때는 아무것도 보내지 않음
Permissions-Policy
사이트에서 카메라를 사용하지 않는다면, 페이지의 스크립트가 카메라에 접근할 수 있어야 할 이유가 없습니다.
빈 괄호는 어떤 출처도 허용되지 않음을 의미합니다. 공격자가 악성 코드를 삽입해도 이 API에 접근할 수 없습니다.
자신의 출처에 특정 기능을 허용하려면:
크로스 출처 격리 헤더
세 가지 헤더가 함께 작동하여 페이지를 크로스 출처 간섭으로부터 격리합니다:
Cross-Origin-Embedder-Policy (COEP):
리소스가 페이지에 로드되려면 명시적으로 허용을 선언해야 합니다.
Cross-Origin-Opener-Policy (COOP):
브라우징 컨텍스트를 크로스 출처 페이지로부터 격리합니다.
Cross-Origin-Resource-Policy (CORP):
어떤 출처가 리소스를 로드할 수 있는지 제어합니다.
이 헤더들은 SharedArrayBuffer 같은 강력한 기능을 활성화하면서 동시에 Spectre 계열 공격으로부터 보호합니다.
구현
Nginx:
Apache:
Node.js with Helmet:
Helmet은 주요 보안 헤더들에 대해 적절한 기본값을 자동으로 설정해줍니다.
헤더 테스트
securityheaders.com이나 Mozilla Observatory에서 현재 설정을 점검해보세요. 브라우저 개발자 도구로 직접 확인할 수도 있습니다: 네트워크 탭을 열고, 요청을 클릭한 뒤, 응답 헤더를 살펴보세요.
HSTS와 CSP부터 시작하세요—이 두 가지가 가장 큰 보호 효과를 제공합니다. 나머지는 순차적으로 추가하세요. CSP는 정책이 충분히 검증될 때까지 Report-Only 모드를 활용하세요.
보안 헤더는 몇 줄의 설정만으로 공격 유형 전체를 차단할 수 있는 드문 방어 수단입니다. 브라우저가 코드의 빈틈을 메우는 든든한 조력자가 됩니다.
보안 헤더에 관한 자주 묻는 질문
보안 헤더가 안전한 코딩 관행을 대체하나요?
아니요. 보안 헤더는 심층 방어의 일부입니다—애플리케이션 코드를 통과한 공격을 잡아냅니다. 안전장치이지 대체물이 아닙니다. 입력 검증, 출력 인코딩, 안전한 인증은 여전히 필요합니다. 헤더는 그런 조치들이 실패할 때 보호해줍니다.
최소한 구현해야 할 보안 헤더는 무엇인가요?
이 네 가지로 시작하세요: Strict-Transport-Security(HTTPS 강제), Content-Security-Policy(XSS 방지), X-Content-Type-Options: nosniff(MIME 혼동 방지), X-Frame-Options: DENY 또는 CSP frame-ancestors(클릭재킹 방지). 이것들이 가장 흔한 공격 경로를 커버합니다.
CSP는 왜 제대로 설정하기 어렵나요?
CSP는 설계상 기존 동작을 차단합니다. 스크립트를 로드할 수 있는 위치를 제한하면, 정책과 일치하지 않는 스크립트는 아무 메시지도 없이 차단됩니다. Report-Only 모드로 시작하고, 위반 사항을 분석하고, 적용 전에 정책을 조정하세요. 여러 번의 조정 과정을 예상하세요—CSP를 올바르게 설정하는 데는 시간이 걸립니다.
X-XSS-Protection을 여전히 설정해야 하나요?
현대 브라우저들은 CSP를 위해 이 헤더를 더 이상 지원하지 않습니다. 일부 보안 전문가들은 구형 브라우저에서 발생할 수 있는 특수한 우회 사례를 막기 위해 X-XSS-Protection: 0으로 명시적으로 비활성화할 것을 권장합니다. 강력한 CSP를 구축하는 데 집중하세요.
이 페이지가 도움이 되었나요?