티스토리 뷰
1. CORS 개념
2. CORS 기능 설명
3. CORS 사용 예시
1. CORS 개념
교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다. 웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행한다.
- 교차 출처 요청의 예시
http://localhost:3001의 프론트엔드 JavaScript 코드가 XMLHttpRequest를 이용하여 http://localhost:4001/data.json을 요청하는 경우
보안 상의 이유로, 브라우저는 스크립트에서 시작한 교차 출처 HTTP 요청을 제한한다. XMLHttpRequest와 Fetch API는 동일 출처 정책(Same-Origin Policy, SOP)을 따른다. 즉, 이 API를 사용하는 웹 애플리케이션은 자신의 출처와 동일한 리소스만 불러올 수 있으며, 다른 출처의 리소스를 불러오려면 그 출처에서 올바른 CORS 헤더를 포함한 응답을 반환해야 한다.
CORS 체제는 브라우저와 서버 간의 안전한 교차 출처 요청 및 데이터 전송을 지원한다. 최신 브라우저는 XMLHttpRequest 또는 Fetch와 같은 API에서 CORS를 사용하여 교차 출처 HTTP 요청의 위험을 완화한다. CORS는 다른 출처의 리소스가 필요한 경우, SOP를 우회하기 위한 여러가지 방법 중 가장 권장되는 방법이다.
Q. SOP와 같은 정책이 존재하는 이유는 무엇일까?
만약 다른 출처의 애플리케이션이 서로 통신하는 것에 대해 아무런 제약도 존재하지 않는다면, 악의적인 사용자가 소스 코드를 보고 CSRF(Cross-Site Request Forgery)나 XSS(Cross-Site Scripting)와 같은 해킹 방법을 사용하여 정보를 탈취할 수 있다.
2. CORS 기능 설명
CORS 표준은 웹 브라우저에서 해당 정보를 읽는 것이 허용된 출처를 서버에서 설명할 수 있는 새로운 HTTP 헤더를 추가함으로써 동작한다.
추가적으로, 서버 데이터에 side effect를 일으킬 수 있는 HTTP 요청 메소드(GET을 제외한 HTTP 메소드)에 대해 CORS는 브라우저가 요청을 options 메소드로 사전 전달(preflight)하여 지원하는 메소드를 요청하고, 서버의 "허가"가 떨어지면 실제 요청을 보내도록 요구한다.
또한, 서버는 클라이언트에게 요청에 "인증정보(쿠키, HTTP 인증)"를 함께 보내야 한다고 알려줄 수도 있다.
CORS 사용에 문제가 발생했을 때 보안상의 이유로 JavaScript에서는 오류의 상세 정보에 접근할 수 없으며, 알 수 있는 것은 오류가 발생했다는 사실 뿐이다. 정확히 어떤 것이 실패했는지 알아내려면 브라우저의 콘솔을 확인해야 한다.
CORS 관련 HTTP 헤더는 다음과 같다.
요청 헤더
- Origin : cross-site 접근 요청 또는 preflight request의 출처
- Access-Control-Request-Method : 실제 요청 메소드
- Access-Control-Request-Headers : 실제 요청의 추가 헤더
응답 헤더
- Access-Control-Allow-Origin : 서버 측 허가출처
- Access-Control-Allow-Credentials : 인증 정보 포함
- Access-Control-Expose-Headers
- Access-Control-Max-Age : Preflight 응답 캐시기간
- Access-Control-Allow-Methods : 허용하는 메소드
- Access-Control-Allow-Headers : 허용하는 헤더
CORS 동작 방식에는 크게 3가지가 있다.
(1) 프리플라이트 요청 (Preflight Request)
Preflight Request는 요청을 예비 요청과 본 요청으로 나눈다. options 메소드를 통해 다른 도메인의 리소스에 요청이 가능한지 (실제 요청을 전송하기에 안전한지) 확인 작업을 하고, 요청이 가능하다면 실제 요청을 보낸다. Cross-Origin 요청은 유저 데이터에 영향을 줄 수 있기 때문에 Preflight 요청을 한다.
(2) 단순 요청 (Simple Request)
Simple Request는 Preflight Request와 다르게 요청을 보내면서 즉시 cross origin인지 확인하는데, 다음 조건을 모두 충족해야 한다.
- 메소드는 GET, POST, HEAD 중 하나
- 헤더는 Accept, Accept-Language, Content-Language, Content-Type만 허용
- Content-Type 헤더는 application/x-www-form-urlencoded, multipart/form-data, text/plain만 허용
(3) 인증정보 포함 요청 (Credentialed Request)
인증 관련 헤더를 포함할 때 사용하는 요청이다. 브라우저가 제공하는 비동기 리소스 요청 API인 XMLHttpRequest 객체나 fetch API는 별도의 옵션 없이 브라우저의 쿠키 정보나 인증과 관련된 헤더를 기본적으로 요청에 담지 않으므로, credentials 옵션을 변경하지 않으면 cookie를 주고 받을 수 없다.
만약 XMLHttpRequest, jQuery의 ajax, 또는 axios를 사용한다면 withCredentials 옵션을 true로 설정해주어야 한다.
반면, fetch API를 사용한다면 credentials 옵션을 include로 설정해주어야 한다.
fetch API의 credentials 옵션은 3가지가 있다.
- omit : 절대로 cookie들을 전송하거나 받지 않는다.
- same-origin : 동일 출처(same origin)라면 user credentials (cookie, basic http auth 등)을 전송한다. (default 값)
- include : cross-origin 호출이라 할지라도 언제든지 user credentials을 전송한다.
3. CORS 사용 예시
Node.js의 back-end 서버에 아래의 명령어로 cors를 설치한다.
$ npm i cors
package.json 파일에 들어가 cors가 잘 설치되었는지 확인한 후, 백엔드 server.js에 다음과 같은 문구를 추가한다.
// 백엔드 server.js (http://localhost:4001)
const cors = require('cors');
app.use(cors({
origin:true,
credentials:true,
}));
이제 프론트에서 axios로 백엔드 서버에 요청을 보낼 때 다음과 같이 작성하면 된다.
// 프론트 서버 /board/write.html (http://localhost:3001)
async () => {
const body = {
subject,
contenct
};
const options = {
'Content-type':'application/json',
withCredentials:true
};
const response = await axios.post('http://localhost:4001/api/board/write', body, options);
}
axios로 post 요청을 보낼 때 백엔드 서버의 URI와 body, 그리고 options 이렇게 3가지 인자 값을 적어준다.
get 요청을 보낼 때에는 body를 제외한 2개의 인자만 넣어주면 된다.
- Total
- Today
- Yesterday
- bom
- keyword
- int
- Screen 객체
- Navigator 객체
- 리액트 #React #props #state #javascript
- c언어
- 키워드
- History 객체
- window 객체
- 자료형
- location 객체
- short
- stdio.h
- Char
- 변수
- 컴파일
- gcc
- DOM
- Document Object Model
- Browser Object Model
- long
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |