728x90
반응형
1. SOP 동일 출처 정책?
▶ SOP(Same-Origin Policy)
웹브라우저의 보안정책으로, 서로 다른 출처의 리소스 간 데이터 접근을 제한한다.
동일 출처란?
먼저 출처(Origin): 프로토콜 + 도메인 + 포트로 구성되어 있다. 이 세가지가 동일해야지만 동일 출처이다!
▶ SOP의 역할
- 보안강화 : 동일출처 정책은 위험할 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄여주는 역할을 수행한다 만약 이런 제약이 없다면 CSRF (Cross-Site Request Forgery) 나 XSS(Cross-Site Scripting)등의 공격에 매우 취약해질 가능성이 생긴다.
- 자동 로그인 예시: 브라우저는 로그인시 발급된 토큰이나 쿠키를 저장한다. 동일한 출처에 재접속 시 이 정보가 자동으로 포함되어 자동 로그인이 가능하다.
2. CORS란?
CORS(Cross-Origin Resource Sharing) SOP의 제약을 안전하게 우회할 수 있는 방법이다.
▶ CORS의 필요성
- SOP로 인해 다른 출처의 리소스에 접근할 수 없지만, 실제로는 API 요청 등으로 다른 서버와 통신할 필요가 많다.
- CORS는 서버가 특정 출처에 대해 접근을 허용하도록 설정할 수 있는 방식이다.
▶ CORS 동작 원리
- 클라이언트가 다른 출처에 요청을 보냄.
- 서버는 요청의 헤더에 포함된 Origin 값을 확인.
- 서버가 해당 Origin을 허용했다면, 브라우저는 요청을 정상적으로 처리.
- 허용되지 않았다면, 브라우저는 CORS 에러를 발생시킴.
3. CORS의 접근제어 시나리오
1. 프리플라이트 요청(Preflight Request)
- 조건: 요청에 커스텀 헤더, PUT/DELETE 메서드, 혹은 Content-Type이 application/json인 경우.
- 동작:
- 브라우저가 OPTIONS 메서드를 통해 다른 도메인의 리소스에 요청이 가능한지 사전 요청을 보냄.
- 서버가 허용하면 본 요청(Actual Request)을 진행.
2. 단순 요청(Simple Request)
- 조건: GET, POST, HEAD 메서드를 사용하고, 커스텀 헤더가 없는 경우.
- 특징: 별도의 사전 요청 없이 바로 서버에 요청.
3. 인증 정보 포함 요청(Credentialed Request)
- 특징: 쿠키나 인증 토큰을 포함한 요청.
- 서버 설정 필요: 서버는 Access-Control-Allow-Credentials: true와 함께 특정 출처를 허용해야 함.
3-1. 프리플라이트 요청과 응답의 필수 헤더
프리플라이트 요청과 응답 시 반드시 포함되어야 할 헤더들이 있다.
프리플라이트 요청 예시
OPTIONS /doc HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type
요청 헤더 설명
- Origin: 요청의 출처.
- Access-Control-Request-Method: 실제 요청에서 사용할 메서드.
- Access-Control-Request-Headers: 실제 요청에 포함될 추가 헤더.
프리플라이트 응답 예시
HTTP/1.1 204 No Content
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2
Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
응답 헤더 설명
- Access-Control-Allow-Origin: 서버가 허용한 출처.
- Access-Control-Allow-Methods: 서버가 허용한 메서드.
- Access-Control-Allow-Headers: 서버가 허용한 헤더.
- Access-Control-Max-Age: 프리플라이트 응답을 캐시할 시간(초 단위).
프리플라이트 응답의 특징
- 응답 코드는 200번대여야 한다.
- 응답 바디는 비어 있는 것이 좋다.
4. CORS 에러가 발생하는 이유
주요 원인
- 서버 설정 미비: 백엔드에서 CORS 설정을 하지 않은 경우.
- 허용되지 않은 출처: 서버가 요청한 Origin을 허용하지 않았을 때.
- 프리플라이트 요청 실패: 복잡한 요청을 보내기 전에 사전 확인 단계에서 실패.
5. CORS 해결방법
1. 서버 설정
Express (JavaScript):
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({ origin: 'https://mywebsite.com' })); // 특정 출처 허용
app.get('/data', (req, res) => {
res.json({ message: 'CORS 요청 성공!' });
});
app.listen(3000, () => console.log('서버 실행 중'));
Django (Python):
- django-cors-headers 설치
pip install django-cors-headers
- settings.py 설정
INSTALLED_APPS = [
...,
'corsheaders',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
...,
]
CORS_ALLOWED_ORIGINS = [
'https://mywebsite.com',
]
2. 프록시 서버 사용
개발 환경에서는 프록시 서버를 설정해 CORS 문제를 우회할 수 있다.
React (Create React App):
- package.json에 프록시 설정 추가:
"proxy": "https://api.example.com"
이렇게 하면 fetch('/data') 요청이 자동으로 https://api.example.com/data로 전송됨
3. 브라우저 플러그인 활용
개발 단계에서는 브라우저 확장 프로그램을 사용해 CORS를 임시로 해결할 수 있다
플러그인 사용은 개발 환경에서만 권장되며, 배포 시에는 서버 설정을 통해 해결해야 한다
- Allow CORS: Access-Control-Allow-Origin (Chrome 확장 프로그램)
참고자료
https://www.youtube.com/watch?v=bW31xiNB8Nc
https://developer.mozilla.org/ko/docs/Glossary/Preflight_request
728x90
반응형