일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- sql like연산자
- lastIndexOf()
- 중복문자제거
- 재귀스왑
- 스프링 데이타 JPA
- 객체를 배열로
- 중복단어제거
- 문자열 중복
- ubuntu타임존
- 레디스 확인
- 객체의 밸류값만 찾기
- 프론트엔드 스쿨
- 문자열순서바꾸기
- 배열을 객체로
- 코딩 어?
- sql 문자열 패턴 검색
- 객체의키값만 찾기
- 깃 토큰 만료
- 시퀄 문법
- indexOf()
- 5.3.8 Modifying Queries
- ...점점점문법
- 단어 제거
- 제로베이스
- js 문자열을 문자배열로
- @Moditying @Query
- 배엘에서 스왑
- 중복 문자열
- 중복된 단어
- 우분투 시간 변경
- Today
- Total
코딩기록
항해 35일) 미니프로젝트- CORS란?, 오류 해결방법 본문
SOP(Same Origin Policy)
다른 출처의 리소스를 사용하는 것에 제한하는 보안 방식
URL의 Protocol, Host, Port를 통해 같은 출처인지 다른 출처인지 판단한다.
CORS가 나온 이유
SOP 보안 정책에 따르면 다른 origin에는 접근이 불가능하다. 하지만, frontend와 backend의 상호작용을 위해서는 다른 orgin에 접근해야할 필요가 있다. 이를 해결하는 답이 바로 CORS(Cross-Origin Resource Sharing)이다.
CORS(Cross-Origin Resource Sharing)
추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제이다. 웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행한다.
현재 브라우저로 접속중인 페이지에서 자바스크립트를 이용해 다른 도메인 또는 포트를 가진 주소로 요청을 하는 경우, 해당 리소스에 접근을 허용했는지 확인해 보안을 높이는 동작을 CORS라고 한다.
CORS 문제는 왜 발생할까?
브라우저는 주소(도메인, 포트 중 하나라도)가 다른 경우 리소스의 출처가 다르다고 판단
- 브라우저에서 출처가 다르다고 판단하면 어떻게 동작할까요?
- 브라우저가 요청하려고 시도했던 주소에 “OPTIONS” 메서드를 이용해 요청을 의도적으로 허용하고 있는게 맞는지 확인합니다. 이것을 CORS preflight 라고 부릅니다.
- 요청을 받은 서버는 평소와 똑같이 응답을 합니다.
- 응답을 받은 브라우저는 요청에 대한 허가를 받지 못했다고 판단하고 CORS 에러를 발생시킵니다.
- 이것은 브라우저에 구현된 비동기 요청 API에서만 동작하는 규칙으로, Thunder Client 같은 API Client를 이용해 요청하는 경우에는 절대 발생하지 않습니다.
CORS 접근제어 시나리오
1. 프리 프라이트 요청 (Preflight Request)
2. 단순 요청 (Simple Request)
3. 인증정보 포함 요청 (Credentialed Request)
1. 프리 프라이트 요청 (Preflight Request)
본 요청을 보내기 전에 서버에게 물어보는 것 (유툽-09:25)
- OPTIONS 메서드를 통해 다른 도메인의 리소스에 요청이 가능한지 확인 작업
- 요청이 가능하다면 실제 요청(Actual Request)을 보낸다.
1). 프리 플라이트 요청 순서
①. 클라이언트가 서버에 Preflight Request사전 요청을 보낸다.
②. 서버가 클라이언트 요청에 Preflight Response사전 응답을 한다. 여기서 요청이 거부가 되면 Actual Request는
보내지지 않는다.
2). 요청 규칙 (유툽 09:50)
①. Preflight Request 사전 요청
- Origin: 요청 출처
- Access-Control-Request-Method: 실제 요청의 메소드
- Access-Control-Request-Headers: 실제 요청의 추가 헤더
Client ----------------------------------------------------------------------------------------------------> Server
②. Preflight Response 사전 응답
- Access-Control-Allow-Origin: 서버 측 허가 출처
- Access-Control-Allow-Methods: 서버 측 허가 메소드
- Access-Control-Allow-Headers: 서버 측 추가 헤더
- Access-Control-Max-Age: Preflight 응답 캐시 기간
Access-Control-Max-Age에 대해 추가로 설명하자면
preflight는 사전 요청과 실제 요청 2번이 보내진다. 하나의 요청에 2번의 요청이 왔다 갔다 하기 때문에 리소스적(프로그램들이 사용할 수 있는 데이터나 루틴)으로 좋지가 않다. 그래서 preflight 응답에 대해서 브라우저는 캐싱을 하고 다음 똑같은 요청을 보낼 때 preflight 캐싱을 확인하고 preflight사전 요청을 보내지 않고 실제 요청을 보낸다.-----(3번의 요청을 한다 가정하면 첫 번째 preflight 응답에 대해서 캐싱을 하고 Access-Control-Max-Age(응답 캐시 시간)에 정한 시간내에 두 번째 요청이 들어오면 사전 요청을 보내지 않고 실제 요청만 한다는 뜻이다.)
Client <---------------------------------------------------------------------------------------------------- Server
③. Preflight Response가 가져야 하는 특징
- 응답 코드는 200대여야 한다.
- 응답 바디는 비어있는 것이 좋다.
3). Preflight Request 흐름
2. 단순 요청 (Simple Request)
- Preflight 요청 없이 바로 요청을 보내고 Cross-origin인지 확인한다.
- 다음 조건을 모두 만족해야 한다.
GET, POST, HEAD 메서드
- Content-Type
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
-헤더는 Accept, Accept-Language, Content-Language, Content-Type 만 허용.
Simple Request흐름
Preflight가 필요한 이유
CORS를 모르는 서버를 위해서다. 좀 더 자세히 설명하자면,
클라이언트가 origin: bom.com을 서버에게 보내면
서버는 origin: bom.com을 우선 해결하고 클라이언트에 응답을 보낸다
서버는 CORS설정을 모르기 때문에 allow-origin이 없다. allow-origin이 없는 상태로 클라이언트에 응답을 보내는데
브라우저 입장에서는 서버한테서 allow-origin을 못 받아서 클라이언트에게 CORS 에러라고 알려준다.
문제는!! 이미 서버 쪽에서 요청을 다 처리한 상태라는 것이다. CORS 에러가 떴다고 해서 서버가 이미 삭제해서 처리한 정보를 되돌릴 수 없기 때문에 이런 문제를 방지하고자 preflight가 필요하다.
만약 클라이언트가 preflight 요청을 보내게 되면 사전 요청 시 서버는 실제로 응답을 처리하지 않고 응답을 브라우저에 보낸다. 브라우저는 allow-origin이 없으니 클라이언트에 CORS에러를 보내고 클라이언트는 CORS에러니까 실제 요청을 보내지 않는다. 그럼 실제 요청이 없으니 서버에 있는 데이터는 아까처럼 삭제되지 않고 안전하게 보호할 수 있다.
3. 인증정보 포함 요청 (Credentialed Request)
- 인증 관련 헤더를 포함할 때 사용하는 요청 (영상 16:39)
- 클라이언트 측
credentials: include
- 서버 측
Access-Control-Allow-Credentials: true
(Access-Control-Allow-Origin: * 은 안됨. 모든 것을 허용하는 순간 에러가 발생해 정확한 origin을 보내야 함.)
쿠키나 jwt토큰을 클라이언트에서 자동으로 담아서 보내고 싶을 때 내 credentials(자격인증서)를 include(포함) 하면 서버 측까지 전달된다. 서버에서도 Access-Control-Allow-Credentials를 true로 해야 클라이언트 측에서 보내는 것을 받을 수가 있다.
CORS 문제 발생 실습
CORS 문제 발생 테스트
1) 작성한 서버 켜기
1) 작성한 서버 켜기
2) https://test-cors.org 접속
개발자도구 > 네트워크탭을 켜놓은뒤 아래와 같이 http://localhost:3000/api주소 를 입력하고 Send Request 버튼클릭.
3) 로컬 서버에 요청해보고 CORS 에러 발생 확인
서버에 요청한뒤 네트워크 탭과 콘솔 탭을 확인해보면 아래와 같이 CORS에러가 발생한것을 확인할 수 있다.
어떻게 하면 CORS가 발생하지 않을 수 있을까?
- CORS 에러를 방지하는 방법은 서버에 Access-Control-Allow-Origin 응답 헤더를 추가하면 된다.
- 모든 요청에 위와 같은 헤더를 추가해주는 cors 라는 이름의 모듈을 사용해 해결한다.
CORS 해결 방법 - Node.js
1) cors 모듈 설치
- 터미널에 명령어를 입력해 CORS 모듈을 설치.
npm install cors
2) 미들웨어 추가
-
- 모든 요청 허용
-
const express = require("express"); const cors = require("cors"); const app = express(); const port = 3000; app.use(cors()); app.get("/cors-test", (req, res) => { res.send("hi"); }); app.listen(port, () => { console.log("서버가 켜졌어요!"); });
- 특정 도메인만 허용
-
const express = require("express"); const cors = require("cors"); const app = express(); const port = 3000; const corsOption = { origin: "https://www.test-cors.org", credentials: true, }; app.use(cors(corsOption)); app.get("/cors-test", (req, res) => { res.send("hi"); }); app.listen(port, () => { console.log("서버가 켜졌어요!"); });
3) 서버 재시작
- 코드를 변경한 뒤엔 서버를 반드시 재시작 해야한다.
4) test-cors.org 에서 해결된 것 확인 다시 http://localhost:3000/api주소 에 요청했을때 아래와 같이 아무런 에러가 나지 않으면 해결된 것이다.
* 블로거들 해결방법 *
[node] CORS란? CORS 문제 해결하기 (tistory.com)
CORS 정책을 위반하여 서로 다른 출처를 가진 상태에서 무언가를 요청하게 되면 브라우저가 보안 상의 이유로 차단을 해버린다!
예를 들어, 클라이언트 포트가 3000번이고 서버의 포트가 8000번 일 때,
클라이언트에서 서버로 리소스를 요청했을 때 CORS 에러 메시지가 클라이언트 콘솔에 빨갛게 뜨고 데이터를 주지 않게 된다.
CORS 문제를 해결하려면 동일한 출처에서 리소스를 요청하면 된다.
node 서버에서 cors 이슈를 해결하는 몇 가지 방법
1. Access-Control-Allow-Origin response 헤더를 추가.
app.get('/', (req,res) => {
res.header("Access-Control-Allow-Origin", "*");
...
}
어떤 특정 요청에만 적용하고 싶다면 cross-origin을 허락하는 헤더를 추가해 문제를 해결할 수 있다.
2. 미들웨어 CORS 추가.
미들웨어 cors를 활용하여 해결할 수 있다.
npm install cors
cors를 설치 한 다음 app.js에 다음을 추가해준다.
const cors = require('cors');
app.use(cors());
만약, 특정 URL만 허용하고 싶다면 다음과 같이 options을 추가해준다.
const cors = require('cors');
const corsOptions = {
origin: "http://localhost:3000",
credentials: true
}
app.use(cors(corsOptions));
함수 형태로도 가능하다.
const cors = require('cors');
const domains = ['http://localhost:3000'];
const corsOptions = {
origin: function(origin, callback){
const isTrue = domains.indexOf(origin) !== -1;
callback(null, isTrue);
}
,
credentials: true
}
app.use(cors(corsOptions));
다른 사람의 cors 해결 방법이다.
나를 너무나 힘들게 했던 CORS 에러 해결하기 😂 :: 자라는 것을 잘하는 개발자 (tistory.com)
5가지 해결 방법
1. 남이 만든 프로시 서버를 사용한다.
2. 직접 프록시 서버를 구축한다.
3. 클라이언트 : http-proxy-middleware 사용한다.
4. 서버 : Access-Control-Allow-Origin 헤더 세팅한다.
5. 서버 : CORS 미들웨어 사용한다.
5가지 중 3가지만 가져왔다.
3. 클라이언트 : http-proxy-middleware 사용하기
위에 기술한 두 번째 해결 방법에서 누락된 방법 중 하나가 바로 http-proxy-middleware 라이브러리를 사용하는 것이다.
배포하고 나서는 동일한 출처에 요청을 하므로 CORS 에러가 발생하지 않지만, 배포하기 전 개발 단계가 문제다.
로컬 환경에서 React는 3000번 포트를 사용하고 Express는 5000번 포트를 사용하기 때문이다.
그러면 3000번 포트에서 5000번 포트로 요청을 보내니까 당연히 CORS 문제가 발생하게 된다.
이는 로컬 환경일 경우에 한정해서 http-proxy-middleware 라이브러리를 사용하여 클라이언트단에서 쉽게 해결할 수 있다.
CRA로 개발 중일 경우, http-proxy-middleware 라이브러리를 설치하고,
setupProxy.js라는 파일을 src 폴더 내에 만들고 아래와 같이 코드를 작성한다.
const { createProxyMiddleware } = require("http-proxy-middleware")
module.exports = function (app) {
app.use(
"/api",
createProxyMiddleware({
target: "http://localhost:5000",
changeOrigin: true,
})
)
}
위와 같이 코드를 작성해 두면, 로컬 환경에서 http://localhost:3000/api로 시작되는 요청을
라이브러리가 http://localhost:5000/api 로 프록싱 해주게 된다.
따라서 브라우저는 클라이언트와 서버의 출처가 다르지만 같은 것으로 받아들이게 되어 CORS 문제를 일으키지 않는다.
4. 서버 : Access-Control-Allow-Origin 헤더 세팅하기
사실 클라이언트에서 해결하는 방법 말고 서버에서 헤더를 세팅해주는 것이 가장 기본적인 CORS 해결 방법이다.
나는 초기에 서버를 따로 구축하지 않고 외부 서버에 리소스를 요청해서 헤더를 세팅할 수 없었기 때문에 프록시 서버를 썼던 것인데,
만약 클라이언트와 서버 모두 자신이 제어할 수 있다면 서버에서 Access-Control-Allow-Origin 헤더를 세팅해주는 것이 가장 좋다.
const express = require('express');
const app = express();
app.get('/api', (req, res) => {
res.header("Access-Control-Allow-Origin", "허용하고자 하는 도메인");
res.send(data);
});
위와 같이 서버 쪽에 코드를 작성해 주면 되는데, Access-Control-Allow-Origin : * 이런 식으로 작성하는 것만은 피하자.
* 를 사용하면 모든 출처에서 오는 요청을 허용하는 것이기 때문에 지양하는 것이 좋고, 허용하고자 하는 도메인을 꼭 작성해주자.
5. 서버 : CORS 미들웨어 사용하기
나처럼 서버를 Express로 구축한 경우 Node.js 미들웨어 중 하나인 CORS를 사용하여 쉽게 문제를 해결할 수 있다.
const express = require('express');
const cors = require('cors');
const app = express();
const corsOptions = {
origin: '허용하고자 하는 도메인',
};
app.use(cors(corsOptions));
origin에 허용하고자 하는 도메인을 넣어주면 response 헤더에 Access-Control-Allow-Origin 내용이 추가가 된다.
app.use(cors()) 이런 식으로 하게 되면 모든 출처에서 오는 요청을 허용하는 것이므로 지양하자.
참고
*유툽 10분 테코 톡
https://www.youtube.com/watch?v=-2TgkKYmJt4
*cors 해결방법-node.js
[node] CORS란? CORS 문제 해결하기 (tistory.com)
* cors 해결방법-프론트(react)개발자
나를 너무나 힘들게 했던 CORS 에러 해결하기 😂 :: 자라는 것을 잘하는 개발자 (tistory.com)
'항해99 > 챕터4 미니프로젝트' 카테고리의 다른 글
항해 36일) Node.js, 백엔드 jwt 토큰, 프론트 없이 Thunder client에서 jwt토큰으로 authMiddleware 게시글생성, 수정, 삭제하기 (0) | 2022.02.14 |
---|