【제15탄】X-Frame-Options, nosniff, Referer 보호! 웹 공격을 근절하는 보안 헤더 완벽 방어
요약
본 글은 웹사이트의 보안을 강화하는 여러 HTTP 응답 헤더(Response Header) 도입 사례를 다룹니다. 클릭 자킹, MIME 스니핑 등 현대적인 웹 공격에 대응하기 위해 X-Frame-Options, Content-Type-Options 등의 보안 헤더를 적용하는 방법을 설명합니다.
핵심 포인트
- X-Frame-Options: SAMEORIGIN으로 iframe 기반의 클릭 자킹 방지
- Content-Type-Options: nosniff로 MIME 스니핑 공격 차단
- 보안 헤더는 API 응답뿐 아니라 모든 정적 파일에 적용해야 함
- 헤더 설정은 비용 제로로 웹 보안을 근본적으로 강화하는 방법임
‘악의적인 사이트가 투명한 iframe으로 게시판을 표시하며, 이용자의 클릭을 가로채는 함정을 설치하고 있었다’
신라 시대에 직접 만든 2ch.biz 스타일 게시판 ‘つゔぁいちゃんねる(2ch.biz)’ 개발 비화의 제15탄입니다. 이번에는 서버 사이드 코드 수정뿐만 아니라, 현대 웹 브라우저가 갖추고 있는 최강의 보안 기능을 최대한 활용하여, 클릭 자킹(Clickjacking)이나 리퍼러 정보 유출을 물리적으로 차단한 보안 헤더 도입 기록을 공개합니다.
SQL 인젝션 방지책(Prepared Statement), XSS Sanitization, Rate Limit, Honey Pot—.
서버 사이드 검증(Validation)을 아무리 완벽하게 구축해도, **‘브라우저의 동작 자체를 제어하는 명령’**을 내리지 않으면 현대의 교묘한 웹 공격을 막을 수 없습니다.
예를 들어, 다음과 같은 공격이 있습니다.
- 클릭 자킹(Clickjacking)
악의적인 공격자가 자신의 사이트에 투명한<iframe>으로 게시판을 겹쳐 표시하여, 사용자가 ‘재미있는 영상을 본다’고 생각했지만 실제로는 뒤에서 게시판의 ‘작성하기’나 ‘계정 삭제’ 버튼을 누르게 만드는 함정. - MIME 스니핑 악용(Content Sniffing)
이미지 파일이나 일반 텍스트로 가져온 콘텐츠 속에 스크립트를 발견한 브라우저가 ‘친절함’으로 멋대로 HTML/JavaScript로 해석·실행해버려 XSS가 발생하는 사고. - 리퍼러(Referer)를 통한 사생활 행동 추적 유출
스레드 내에 붙은 외부 링크를 클릭하여 외부 사이트로 이동했을 때, HTTP 리퍼러 헤더를 통해 ‘어떤 게시판의 어떤 스레드(어떤 취미 주제)를 읽고 있었는지’가 외부 서버에 그대로 노출되는 위험.
이러한 위협들은 웹 서버가 적절한 **‘HTTP 응답 헤더(Response Header)’**를 브라우저에 반환하는 것만으로, 거의 비용 제로로 완벽하게 근절할 수 있습니다.
개발 초기(2026년 8월 18일), つゔぁいちゃんねる의 모든 응답에 **‘엄선된 보안 헤더 그룹’**을 배치했습니다.
つゔぁいちゃんねる가 브라우저에게 항상 전송하는 응답 헤더는 다음과 같습니다.
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
...
제3자의 외부 사이트가 <iframe>이나 <frame> 태그를 사용하여 つゔぁいちゃんねる을 삽입하는 것을 브라우저 레벨에서 금지합니다. 자사 도메인 내에서의 프레임 표시만 허용하여, 투명한 클릭 가로채기 공격을 무력화합니다.
서버가 선언한 Content-Type (예: text/plain이나 application/json)를 브라우저가 멋대로 오해하여 HTML로 실행하는 ‘MIME 스니핑’을 엄금합니다. 부정한 스크립트 혼입의 싹을 자릅니다.
주로 구형 브라우저(IE나 오래된 Edge/Chrome)를 대상으로, XSS 공격 패턴을 감지했을 경우 페이지 전체의 렌더링을 즉시 차단(정지)시킵니다.
스레드 내 링크를 클릭하여 외부 사이트로 이동할 때, URL의 완전한 경로(https://2ch.biz/?thread=123)를 전송하지 않고 도메인명(https://2ch.biz/)만 잘라서 전송합니다. 또한, HTTPS에서 HTTP로 다운그레이드되는 통신에서는 리퍼러를 일절 전송하지 않습니다.
게시판 서비스에는 카메라나 마이크, GPS 위치 정보 이용 권한은 전혀 필요 없습니다. 브라우저에게 ‘이 사이트에서는 그러한 하드웨어 API를 일체 호출하지 않는다’고 선언하여, 악의적인 서드파티 스크립트나 확장 기능에 의한 부정 접근을 근본적으로 봉쇄합니다.
헤더 설정은 API 응답뿐만 아니라, 정적 파일(HTML, CSS, JS)을 포함한 모든 접속에 누락 없이 적용되어야 의미가 있습니다.
정적 파일이나 전체 요청에 대해 Apache 레이어에서 일괄 부여합니다.
<IfModule mod_headers.c>
Header always set X-Frame-Options
function sendSecurityHeaders() {
header('X-Frame-Options: SAMEORIGIN');
header('X-Content-Type-Options: nosniff');
...
구현 후, 프로덕션 및 로컬 환경에 대해 `curl -I` 명령을 실행하여 모든 보안 헤더가 확실하게 브라우저에 도달하는지 검증했습니다.
$ curl -I http://localhost:3000/api.php?action=boards
HTTP/1.1 200 OK
Content-Type: application/json; charset=UTF-8
...
브라우저에서 게시판 화면을 열어봐도 디자인 깨짐이나 기능 장애는 전혀 발생하지 않았으며, 보안 진단 도구(SecurityHeaders.com 등)에서도 고평가를 받을 수 있는 안전한 인프라가 완성되었습니다.
제15회에 걸쳐 이번에는 브라우저의 안전 기능을 최대한 끌어내는 **'보안 헤더 완전 방벽'** 에 대해 설명했습니다.
-
**브라우저로의 명령이 가장 강력한 방패가 되다**: 서버 측 검증과 브라우저의 보안 정책은 두 바퀴와 같습니다. -
**프레임, MIME, 리퍼러의 삼중 방어**: 클릭 자킹(Clickjacking)과 의도치 않은 XSS, 개인 정보 유출을 동시에 저지합니다. -
**기밀 파일의 직접 접근 거부**: `.htaccess`로 데이터베이스 파일(`.db`)이나 설정 파일을 확실하게 보호합니다.
서버 인프라와 관리자의 방어는 완벽해졌습니다.
하지만 게시판에는 2ch 사용자에게 가장 친숙하고 중요한 기능이 하나 더 있습니다.
**'나에게 불쾌한 코테한(코멘트 닉네임)이나 트롤을, 나만의 브라우저에서 보이지 않게 하는 '로컬 아봉(あぼ〜ん)'** 입니다.
다음 편에서는 **【제16회】불쾌한 글은 보지 않는 것이 2ch의 취미! localStorage를 활용한 클라이언트 측 '아봉' 완전 구현**으로 이어집니다!
-
**실제 서비스**: https://2ch.biz/
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기