🌏 SOP (Same-Origin Policy)
웹 브라우저에는 기본적으로 Same-Origin Policy(동일 출처 정책, SOP)라는 제약이 걸려 있습니다. 출처(Origin)는 프로토콜 + 도메인 + 포트 조합으로 결정되고, 브라우저는 이 조합이 완전히 같을 때만 자유롭게 요청, 응답을 통한 데이터 접근을 허용합니다.
이 제약은 보안을 위해 꼭 필요합니다. 만약 이 정책이 없다면, 악성 웹사이트에 접속했을 때 그 사이트의 자바스크립트가 내가 로그인해 둔 은행 사이트의 쿠키나 계좌 정보를 그대로 읽어버릴 수도 있습니다. 따라서 SOP는 브라우저 단에서 다른 출처 간 데이터 접근을 차단하는 안전장치입니다.
SOP가 막는 것들을 정리해 보자면,
✅ 1. DOM 접근 차단
내가 만든 사이트에서 <iframe src="https://bank.com">을 넣었다고 해본다면, SOP 때문에 내 자바스크립트가 iframe 안쪽(=은행 사이트 DOM 구조)에 직접 접근하지 못합니다.
만약 이게 가능했다면? → 악성 사이트가 은행 페이지를 불러서 사용자 계좌 정보를 몰래 읽을 수 있었을 테지만, SOP 덕분에 다른 출처의 화면 안쪽 내용은 볼 수 없습니다.
cf. iframe은 웹페이지 안에 또 다른 웹페이지를 “창”처럼 끼워 넣는 태그입니다. 신문에 붙어 있는 광고 전단처럼, 하나의 HTML 안에 다른 사이트를 그대로 불러올 수 있습니다.
✅ 2. 쿠키 / LocalStorage 차단
어떤 사용자가 은행(bank.com)에 로그인한 상태라면, 그 쿠키나 LocalStorage 안에 세션 토큰이 저장돼 있습니다. 공격자가 만든 사이트(evil.com)에서 JS로 document.cookie를 실행한다고 해도 bank.com의 쿠키는 읽히지 않습니다.
✅ 3. AJAX 응답 읽기 차단
브라우저는 다른 출처 API로 요청을 보내는 것 자체는 허용합니다. 예를 들어, frontend.com에서 api.bank.com으로 AJAX 요청을 보낼 수는 있어요. 하지만 응답을 브라우저가 가로막기 때문에, JS 코드에서 응답 본문을 읽을 수 없습니다. 그래서 “요청은 날아가지만, 응답은 SOP 때문에 볼 수 없다”는 특징이 있습니다. 즉, 데이터 읽기는 막히지만, 요청 자체는 가능합니다.
cf. AJAX란, 웹페이지가 새로고침 없이(부분 갱신) 서버와 데이터를 주고받게 해주는 기술입니다.
하지만 실제 서비스에서는 프론트엔드와 백엔드가 다른 도메인에 있는 경우가 흔합니다. 예를 들어, https://frontend.com 웹앱이 https://api.backend.com API를 호출해야 하는 상황이 있습니다. 이렇게 되면 프론트엔드와 백엔드의 출처가 다르게 되고, SOP 때문에 브라우저가 기본적으로 응답을 막습니다.
이 문제를 해결하기 위해 나온 것이 CORS(Cross-Origin Resource Sharing)입니다.
🌏 CORS (Cross-Origin Resource Sharing)
CORS는 보안을 강화하는 기능이 아니라, 예외를 허용하는 기능입니다.
SOP가 원래 브라우저 보안의 핵심이고, CORS는 개발 편의상 “이 출처만 열어줄게” 하는 장치입니다.
✅ CORS의 동작 원리
- 서버가 응답 헤더에 특정 출처를 허용한다고 명시
- 브라우저는 이를 확인한 뒤 교차 출처 요청을 허용
- 주요 헤더
Access-Control-Allow-Origin: 허용할 출처Access-Control-Allow-Methods: 허용할 HTTP 메서드Access-Control-Allow-Headers: 허용할 커스텀 헤더Access-Control-Allow-Credentials: 브라우저가 쿠키·Authorization 헤더 같은 자격 증명을 요청에 포함할 수 있는지 여부Access-Control-Allow-Credentials: true는Access-Control-Allow-Origin: *와 동시에 사용할 수 없음
⇒ “누구나 + 인증정보까지” 조합이면 보안상 치명적이기 때문
Access-Control-Expose-Headers: 기본적으로 브라우저는 응답 헤더 중 일부만 자바스크립트에 보여주는데, 이 옵션을 통해 필요한 커스텀 헤더를 JS에서 읽을 수 있게 열어줍니다.
예:Access-Control-Expose-Headers: X-Total-Count, X-Request-IdAccess-Control-Max-Age: Preflight(OPTIONS) 요청 결과를 브라우저가 얼마나 오래 캐싱할지 지정합니다. 잘 설정하면 매번 OPTIONS를 보내지 않아도 돼서 성능이 좋아집니다.
예:Access-Control-Max-Age: 3600
✅ Preflight Request (사전 요청)
일부 민감한 요청은 그냥 실행하지 않고, 먼저 OPTIONS 요청을 보내 서버에 “이 요청 보내도 되나요?”라고 묻습니다.
- 브라우저 → 서버: Preflight(
OPTIONS) 요청 전송 - 서버 → 브라우저: CORS 관련 허용 헤더 응답
- 브라우저 → 서버: 실제 요청 전송
이 과정을 통해 보안을 해치지 않으면서도 필요한 경우 교차 출처 요청을 안전하게 수행할 수 있습니다.
✔️ Preflight (OPTIONS) 요청은 매번 보내나요?
브라우저 입장에서 보면, Preflight는 일종의 안전 확인 절차입니다. “이 요청을 그냥 보내면 혹시 보안 사고가 나지 않을까?” 하고 걱정되는 경우에만 OPTIONS로 먼저 물어보게 됩니다. 따라서 단순한 요청에는 OPTIONS 요청을 보내지 않게 됩니다.
- 단순한 요청 (예: GET으로 이미지 가져오기, 폼 데이터 전송 등)은 웹에서 아주 오래 전부터 안전하게 쓰여왔습니다. 이런 건 굳이 매번 서버한테 허락을 구하지 않아도 괜찮다고 판단합니다. 그래서 바로 본 요청을 보냅니다.
- 예: GET/POST/HEAD 중
Content-Type이application/x-www-form-urlencoded,multipart/form-data,text/plain중 하나일 때
- 예: GET/POST/HEAD 중
- 반대로 조금 특수하거나 민감한 요청 (예: JSON POST, Authorization 헤더, PUT/DELETE 같은 메서드)은 보안적으로 민감할 수 있습니다. 그래서 브라우저가 직접 서버에 먼저 “이런 요청 보내도 되나요?”라고 묻는 과정을 거칩니다.
✔️ Preflight 캐싱
- Preflight(OPTIONS) 요청은 매번 보내지 않고 브라우저가 캐시할 수 있습니다.
- 서버 응답 헤더
Access-Control-Max-Age값만큼 캐시되며, 그 시간 동안은 OPTIONS 요청을 생략합니다. - 즉, “OPTIONS가 무조건 매번 나가는 게 아니라, 서버 설정에 따라 줄일 수 있다”는 점이 중요합니다.

도움이 되었다면, 공감/댓글을 달아주면 깃짱에게 큰 힘이 됩니다!🌟
비밀댓글과 메일을 통해 오는 개인적인 질문은 받지 않고 있습니다. 꼭 공개댓글로 남겨주세요!
'컴퓨터과학 > 네트워크' 카테고리의 다른 글
| [네트워크] 패킷이 이동하는 과정, 포장부터 개봉까지: 브라우저에 깃짱코딩.com을 입력하면 무슨 일이 일어나나요? (0) | 2025.09.13 |
|---|---|
| [네트워크] TCP/IP 헤더와 패킷의 구조 (0) | 2025.09.13 |
| [네트워크] 웹 보안 공격들(XSS, CSRF, SQLi, DDos 등등): 공격 방법과 방어 전략 (0) | 2025.09.12 |
| [네트워크] 인증을 구현하는 방법들: 클라이언트는 쿠키 이외에 인증 정보를 어디에 저장할 수 있을까? (0) | 2025.09.11 |
| [네트워크] HTTP Header: Virtual Hosting, 컨텐츠 협상, Accept의 우선순위, Authorization, Cache-Control (0) | 2025.09.10 |