보안 헤더와 CSP, 브라우저에게 미리 걸어 두는 제약
브라우저에 보안 규칙을 전하면 필요한 기능도 멈출 수 있어요. 파일 종류, HTTPS, CSP의 역할을 나누고 적용 순서를 생각해 봐요.
이 글의 목차응답에 붙는 한 줄이 실행 규칙이 된다4
웹에는 다른 소프트웨어에 없는 성질이 하나 있어요. 제가 만든 것이 제 서버가 아니라 방문자의 브라우저에서 실행된다는 점이에요. 그 브라우저는 내 것이 아니고, 그 안에서 무엇이 함께 도는지도 제가 정하지 못해요.
서버는 응답에 보안 헤더, 곧 브라우저가 따라야 할 보안 규칙을 붙일 수 있어요. 외부 스크립트를 어디까지 허용할지 같은 약속이에요. 그런데 필요한 파일까지 막으면 멀쩡한 기능도 멈춰요. 어떤 위협을 줄이는지와 어떤 동작이 함께 영향을 받는지를 짝으로 배워 두면 설정을 이해하기 쉬워요.
응답에 붙는 한 줄이 실행 규칙이 된다
가장 단순한 예가 파일 종류를 두고 벌어지는 일이에요. 브라우저는 서버가 알려 준 종류와 실제 내용이 어긋날 때 내용을 보고 종류를 추측해요. 이 추측 알고리즘 자체가 표준 문서로 정리돼 있을 만큼 오래된 동작이에요. 편의를 위한 동작이었지만, 사용자가 올린 이미지가 스크립트로 해석되는 길을 열어 주기도 했어요. 추측하지 말고 알려 준 대로만 다루라고 요구하는 헤더가 이 문제를 닫아요.
같은 방식으로 브라우저의 여러 동작에 제약을 걸 수 있어요. 다른 사이트가 내 페이지를 자기 화면 안에 끼워 넣지 못하게 하거나, 링크를 타고 나갈 때 어느 주소에서 왔는지를 어디까지 알려 줄지 정하거나, 카메라와 위치 같은 기능을 쓰지 않겠다고 미리 선언하는 식이에요. 공통점은 하나예요. 서버가 자기 페이지의 실행 환경에 대해 무엇을 하지 않을 것인지 미리 말해 두는 일이에요.
첫 요청이라는 구멍
HTTP로 들어온 요청을 HTTPS로 돌려보내는 방식에는 첫 연결의 틈이 있어요. 브라우저가 처음부터 HTTPS를 시도하기도 하지만, 실제로 HTTP 요청이 먼저 나갔다면 서버의 전환 응답을 받기 전에 그 요청은 네트워크를 지나가요. 그 연결을 가로채는 공격을 전환 응답만으로 막을 수는 없어요.
2012년 11월에 나온 RFC 6797은 이 구멍을 브라우저의 기억으로 메워요. 서버가 한 번 이 도메인은 앞으로 안전한 연결로만 접속하라고 선언하면, 브라우저가 그 사실을 기간과 함께 저장해 두고 다음부터는 http로 나가려는 시도를 자기 선에서 https로 바꿔요. 첫 요청 이후의 모든 요청이 보호되는 셈이에요.
이 약속이 HSTS(HTTP Strict Transport Security)예요. MDN의 HSTS 설명처럼 브라우저가 아직 정책을 받지 않은 첫 방문에는 공백이 남아요. 브라우저에 목록을 미리 넣는 프리로드는 그 공백을 줄이지만 되돌리는 데도 시간이 걸려요. 정책을 기억하는 동안 인증서가 잘못되면 접속을 막으므로, HTTPS를 계속 제공할 준비와 함께 결정해야 해요.
허용 목록으로 뒤집기
이 시리즈의 포트와 방화벽 편에서 다룬 원칙이 브라우저 안에서도 반복돼요. 무엇을 막을지 세는 대신 무엇을 허용할지 세는 방식이에요. 2016년 12월 15일 W3C 권고가 된 콘텐츠 보안 정책이 그 장치예요. 이 페이지에서 스크립트는 어디서 온 것만 실행하고, 스타일과 이미지는 어디까지 허용하는지를 서버가 선언하면 브라우저가 그 밖의 것을 차단해요.
문제는 실제 페이지가 생각보다 많은 곳에서 자원을 끌어온다는 점이에요. 분석 스크립트, 폰트, 지도, 결제창이 각자 다른 주소를 쓰고, 그중 하나를 빠뜨리면 그 기능이 조용히 멈춰요. 그래서 이 정책에는 차단하지 않고 위반만 보고하는 모드가 함께 있어요. 먼저 그 모드로 켜서 무엇이 걸리는지 며칠 모으고, 목록을 다듬은 뒤에 실제 차단으로 넘기는 것이 정석이에요.
| 규칙 | 줄이는 위험 | 잘못 걸면 |
|---|---|---|
| 파일 종류 추측 제한 | 스크립트·스타일이 잘못된 종류로 실행됨 | 잘못 표시한 정상 자원도 차단 |
| HSTS로 HTTPS 사용 기억 | 정책을 아는 브라우저의 HTTP 접속 | 인증서 문제 때 접속 불가 |
| CSP로 실행 자원 제한 | 허용하지 않은 스크립트 실행 | 필요한 자원까지 차단 |
콘텐츠 보안 정책은 CSP(Content Security Policy)라고도 불러요. 위반은 브라우저 콘솔이나 수집한 보고서에서 볼 수 있어요. 서버가 정상 응답을 줬다는 사실만으로는 브라우저가 그 자원을 실행했는지 알 수 없다는 점이 중요해요. 보고 전용 모드는 실제 기능을 막기 전에 그 차이를 살펴볼 기회를 줘요.
허용 목록에서 빠진 예시 지도 스크립트를 두 정책으로 비교해 보세요.
- 본문 HTML정상 응답
- 지도 스크립트위반 표시 · 허용
- 지도 기능실행됨
- 본문 HTML정상 응답
- 지도 스크립트요청 차단
- 지도 기능실행 안 됨
같은 허용 목록이라도 보고 전용은 위반을 관찰하고, 강제 정책은 허용하지 않은 자원의 실행을 막아요.
보고 전용 정책은 위반을 알리지만 이 정책으로 스크립트를 막지는 않아요.
다른 차단 정책이 없는 예시예요. 실제 지도·외부 스크립트·보고 수집기를 연결하거나 이 사이트의 보안 정책을 바꾸지 않아요.
저는 무엇을 걸어 두었나
이 블로그는 아직 단순한 편이라 걸어 둔 것도 단순해요. 종류를 추측하지 말라는 요구, 다른 사이트가 화면에 끼워 넣지 못하게 하는 제한, 링크를 타고 나갈 때 주소를 어디까지 넘길지에 대한 규칙, 그리고 쓰지 않는 기기 기능을 쓰지 않겠다는 선언 정도예요.
이 블로그에서는 현재 사용하는 자원과 실제 응답 헤더를 기준으로 범위를 정했어요. 외부 서비스를 추가하면 그때 필요한 출처와 데이터 수집 여부를 다시 검토해야 해요. 아직 쓰지도 않는 서비스 때문에 미리 넓게 허용해 둘 필요는 없어요.
이 설정들은 켜는 순간 안전해지는 스위치가 아니라, 내 페이지가 무엇에 의존하고 있는지 스스로 아는 만큼만 조일 수 있는 물건이었어요.