CORS (Cross Origin Resource Sharing)
- 교차 출처 리소스 공유 정책
- 출처가 다른 리소스끼리 공유가 가능하게 전제함
SOP
- 동일 출처 정책
- SOP는 동일한 출처에만 리소스를 공유할 수 있음을 전제함
- SOP는 동일한 출처(프로토콜 + 도메인 + 포트번호)에 있는 리소스만 가져올 수 있음을 의미
CORS에러 발생원인
- 자바스크립트는 기본적으로 SOP정책을 따르기 때문에 fetch, axios로 다른 출처가 다른 서버에 요청을 보냈을때 브라우저에서 응답값의 출처를 확인한후 출처가 다를 경우 CORS에러 발생
- api를 요청한 클라이언트의 출처(origin)과 요청을 받는 서버의 출처(origin)이 다를떄 CORS에러 발생
- 서버에서 온 응답을 브라우저에서 확인하고 응답을 분석하여 출처(origin)가 다를때 브라우저에서 요청을 막음
출처(Origin)
- 클라이언트의 프로토콜, 도메인,포트번호와 서버의 프로토콜, 도메인,포트번호 가 같을때 출처가 같다
- 자바스크립트에서 현재 사이트의 origin을 알아내는 코드
console.log(location.origin); // "https://www.naver.com" (포트 번호 80번은 생략됨)
출처 비교 기준
- Protocol(Schema): http, https
- Host : 사이트 도메인
- Port : 포트번호
- Path : 사이트 내부 경로
- Query string 요청의 key와 value
- Fragment: 해시 태그
CORS 에러 발생시켜보기
- index.html에서 fetch로 localhost:3000으로 요청시 출처가 달라 CORS에러를 발생시키고 Access-Control-Allow-Origin의 헤더가 다르다는 에러 반환
해결방법
서버에서 Access-Controll-Allow-Oringin 헤더 세팅
# 헤더에 작성된 출처만 브라우저가 리소스를 접근할 수 있도록 허용함.
# * 이면 모든 곳에 공개되어 있음을 의미한다.
Access-Control-Allow-Origin : https://naver.com
# 리소스 접근을 허용하는 HTTP 메서드를 지정해 주는 헤더
Access-Control-Request-Methods : GET, POST, PUT, DELETE
# 요청을 허용하는 해더.
Access-Control-Allow-Headers : Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization
# 클라이언트에서 preflight 의 요청 결과를 저장할 기간을 지정
# 60초 동안 preflight 요청을 캐시하는 설정으로, 첫 요청 이후 60초 동안은 OPTIONS 메소드를 사용하는 예비 요청을 보내지 않는다.
Access-Control-Max-Age : 60
# 클라이언트 요청이 쿠키를 통해서 자격 증명을 해야 하는 경우에 true.
# 자바스크립트 요청에서 credentials가 include일 때 요청에 대한 응답을 할 수 있는지를 나타낸다.
Access-Control-Allow-Credentials : true
# 기본적으로 브라우저에게 노출이 되지 않지만, 브라우저 측에서 접근할 수 있게 허용해주는 헤더를 지정
Access-Control-Expose-Headers : Content-Length
Node에서 express로 cors헤더 셋팅하기
직접 헤더에 명시
res.setHeader('Access-Control-Allow-origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true'); // 쿠키 주고받기 허용
res.end();
CORS 미들웨어 사용
- cors 패키지 설치
> npm i cors
- origin: 허용출처 설정
- credential: 다른 도메인 간에 쿠키 공유를 허락하는 옵션
const express = require('express')
const cors = require('cors');
const app = express();
app.use(cors({
origin: true, // 출처 허용 옵션
credential: true // 사용자 인증이 필요한 리소스(쿠키 ..등) 접근
}));
- DB에서 등록된 도메인인지 조회
- 만약 등록된 도메인이라면, 클라이언트에서 보낸 origin을 허용하게 설정 origin : req.get('origin')
//* cors 전용 라우터
router.use(async (req, res, next) => {
// api서버로부터 발급받은 허용된 사용자인지 DB로 체크
const domain = await Domain.findOne({
where: { host: new URL(req.get('origin'))?.host }, // 브라우저에서 요청 헤더에 origin을 넣어서 보낸걸 받는다.
});
if (domain) {
// 만약 api서버로부터 발급받은 허용된 사용자라면, cors 설정해주기
cors({
origin: req.get('origin'), // origin : true 모두 허용하면 보안상 위험하니까
credentials: true, // 쿠키 통신 설정 : 인증된 요청
})(req, res, next); //? 미들웨어 확장 패턴 : 그냥 router.use(cors()) 이렇게 쓰지말고 조건에 따라 미들웨어가 실행괴게 할 수 있다.
} else {
next(); // 만일 등록된 도메인이 아니라면 그대로 보내줘서 cors 에러뜨게 놔둔다.
}
});
참고블로그:
[NODE] 📚 cors 모듈 - CORS 간편 설정하기
CORS 허용 설정 하는 방법 Node.js 서버 프로젝트에서 cors(cross origin resource sharing) 문제를 해결하는 방법은 크게 2가지가 있다. 하나는 직접 헤더를 명시해서 출처(origin)을 필터링하는 것이고, 다른
inpa.tistory.com